PHP: __ set işlevi davranışı her seferinde farklı

3 Cevap

Bu nesneye yeni bir özellik oluşturmak için yönetir. Ancak, birisi setAttrib iki farklı şekilde davranır neden destekleyen bağlantıları ile açıklayabilir? Neden bir neden olmaz ... wait for it ... yığın taşması!?

class Test
{
  public function setAttrib( $key, $value ) {
    echo "setAttrib\n";

    // first time: calls $this->__set($key, $value)
    // second time: just sets a public property (but, when exactly was it created?)
    $this->$key = $value;
  }

  public function __set( $key, $value ) {
    echo "__set\n";
    $this->setAttrib($key, $value);
  }
}

$test = new Test();
$test->setAttrib('hey', 'It works');
var_dump($test);

üretir ...

setAttrib
__set
setAttrib
object(Test)#1 (1) {
  ["hey"]=>
  string(8) "It works"
}

Düzenleme: Ben bir alternatif aramıyorum. I'm looking for the reason why this works.

3 Cevap

this comment on the manual's page şöyle der: Sen yinelemeli olmayan davranış olduğunu fark var gibi görünüyor tek değildir:

2 - PHP will not recursively call one magic method from within itself (at least for the same $name).

Ve, biraz sonra aynı sayfada, hangi devletler, this one var:

The recursion detection feature can prove especially perilous when using __set. When PHP comes across a statement that would usually call __set but would lead to recursion, rather than firing off a warning or simply not executing the statement it will act as though there is no __set method defined at all.
The default behaviour in this instance is to dynamically add the specified property to the object thus breaking the desired functionality of all further calls to __set or __get for that property.


And, on PHP's bugtracker, there is #47215 : magic method __set() is bypassed on recursive call, which says :

Magic method __set() is bypassed on recursive call.
PHP automatically creates a property on instance instead of recursively calling __set() or instead of throwing a recursivity error

Ve o kapalı olduğu gibi:

Thank you for taking the time to write to us, but this is not a bug.

Bu hata raporu, kendisi, bu cümle ile biter, this blog-post işaret (quoting, emphasis mine):

After all I think it may not be a bug but expected behaviour, otherwise we could not be able to define object properties from within __set() method.

erişilemeyen özellikler yazarken __set yalnızca kullanılır. Yani, (özel veya korunan) erişilebilir olmayanlar veya hiç ayarlanmamış olanlar. Bu nedenle, __ set yalnızca bir kez çağrılır.

İşte ne var:

  • setAttrib: yazma girişimi
  • sınıf: ulaşılmaz özellik
  • __set: kümesi tekrar çağrı setAttrib, hangi yapmak için söyledim ne olursa olsun __ yapın.
  • setAttrib: yazma girişimi
  • sınıf: ulaşılmaz özellik, but __set can't recurse, and we're already in it, so do it as if __set didn't exist.

__ Set özyineleme olamayacağını ispat için http://php.net/%5F%5Fset için kullanıcı yorumları görmek.

__set ve üye korunuyorsa __get, yalnızca özellik için çağrı yakalamak. nesnenin içinde $this->$key özelliğini ayarlar, yani $key. kapsam dışında çağrıldığında eğer __set mantık denir. Aramalarınızın biri nesnenin dışında nesne olur.