Req #71254 [Opn]: Allow limited recursion with __get().
[email protected] ("andreas at dqxtech dot net")
| Newsgroups | php.bugs |
|---|---|
| Message-ID | <[email protected]> |
Edit report at https://bugs.php.net/bug.php?id=71254&edit=1
ID: 71254
User updated by: andreas at dqxtech dot net
Reported by: andreas at dqxtech dot net
Summary: Allow limited recursion with __get().
Status: Open
Type: Feature/Change Request
Package: Class/Object related
PHP Version: 7.0.2RC1
Block user comment: N
Private report: N
New Comment:
Hmm.. maybe the correct solution is not a stub, but a proxy (lazy instantiation).
And with that, every key in __get() is only called once.
A single proxy in the loop is sufficient to prevent the recursion and all problems caused by it.
A single stub in the loop is sufficient to prevent infinite recursion. But to also avoid duplicate values in the buffer, one needs one stub per calc_*() method..
There is a trick to only need one stub in the circle:
https://3v4l.org/nXTYJ
But I'm not sure if I really like this, or if proxy is generally better.
Previous Comments:
------------------------------------------------------------------------
[2015-12-31 01:54:26] andreas at dqxtech dot net
Description:
------------
Currently, magic __get() refuses to dive into recursion if the same key is repeated.
https://3v4l.org/00Kuv
It stops, and gives a "Notice: Undefined property: C::$x".
There are cases where the recursion is not a bug, and it is indeed legitimate to dive one level into the recursion.
As we can see, calling ->__get('x') explicitly instead of magic ->x, avoids the notice. But this is undesirable, because we want the IDE to recognize that we are calling @property $x.
The unlimited recursion can be avoided with stubs:
https://3v4l.org/Nb3VF
Proposal:
I want to propose that the recursion detection mechanic only gets active if the same key is used a 3rd time, not the 2nd time. This permits the legitimate case, but still prevents unlimited recursion.
Test script:
---------------
<?php
class C {
private $buffer = array();
function __get($key) {
if (array_key_exists($key, $this->buffer)) {
return $this->buffer[$key];
}
$f = 'calc_' . $key;
return $this->buffer[$key] = $this->$f();
}
function calc_x() {
$x = new stdClass;
// Set a stub to avoid infinite recursion.
$this->buffer['x'] = $x;
$x->y = $this->y;
return $x;
}
function calc_y() {
$y = new stdClass;
// Set a stub to avoid infinite recursion.
$this->buffer['y'] = $y;
$y->x = $this->x;
return $y;
}
}
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=71254&edit=1