Uh oh!
There was an error while loading. Please reload this page.
Implement mechanism for finding prop_info for property slot - #3573
Conversation
nikic
commented
Oct 3, 2018
@bwoebi This would be my solution for #3313 (comment). @dstogov What do you think about this? Part of the motivation here is to fix a tricky edge case for typed properties, but I think that this will also be useful for other things. (E.g. we could implement object iteration without forcing creation of properties HT, which can be a big memory usage problem.) |
dstogov
left a comment
There was a problem hiding this comment.
I think, this idea may make sense for typed properties, but I don't see benefits for foreach, in current state. This new table is going to be created and accessed even for objects with public properties only, that should be more expensive than additional check for public/private properties.
If this is really necessary, probably, better to combine this patch with typed properties.
I'll try to think about this tomorrow once again.
There was a problem hiding this comment.
There is no reason to inline this function. Better, merge it with zend_check_property_info_access().
There was a problem hiding this comment.
Cached classes with ZEND_ACC_LINKED may build this table once and keep it in SHM, instead of rebuilding on each request.
There was a problem hiding this comment.
opcache might need special handling for this field. At least, add an assertion that it's NULL.
There was a problem hiding this comment.
We, probably, may get property name from property_info->name, instead of unmangling.
There was a problem hiding this comment.
property_info->name is a mangled name though. Unmangling is unavoidable here.
bwoebi
commented
Oct 3, 2018
I like the approach (in particular as I cannot imagine a much better approach to this issue), though I'm questioning whether it's worth delaying the initialization at all. At least, like Dmitry hinted at, classes with ZEND_ACC_LINKED will want to persist that information. @dstogov I had that same assumption than you, but as it turns out, you can redeclare a non-static property with the same name in a child class. And we cannot just optimize that redeclaration away as we'd then loose docblock info for reflection. Thus just checking for protected won't work. |
nikic
commented
Oct 3, 2018
Unfortunately there is an ugly test failure relating to ArrayObject that I'm not sure what to do about. The problem is basically that ArrayObject This is not a problem for the typed properties use case (where we'd be directly working on the properties_table, not going through properties HT), but it is a problem for implementing visibility checks. |
nikic
commented
Oct 3, 2018
This behavior also causes issues without this patch in some other cases. For example: class Test {
public$test;
public$test2;
}
classAOextends ArrayObject {
private$test;
publicfunctiongetObjectVars() {
returnget_object_vars($this);
}
}
$ao = newAO(newTest);
var_dump(get_object_vars($ao));
var_dump($ao->getObjectVars());This gives: First, the array only contains the In the second case we get an assertion failure because https://github.com/php/php-src/blob/master/Zend/zend_object_handlers.c#L570 does not hold. I think we need to change get_properties for ArrayObject to always return its own object properties, and additionally overload |
dstogov
commented
Oct 4, 2018
@nikic could you, please, release your ArrayObject related proposal as a bug fix PR and mention compatibility breaks. |
nikic
commented
Oct 4, 2018
Currently there is no efficient way of finding the property_info which corresponds to a given property slot. This patch implements such a mechanism, by storing an array of property_infos in offset order on the class. This structure is lazily initialized when it is needed, though we could also compute it during inheritance. This patch only uses it to optimize visibility checks during foreach (and get_object_vars etc). We avoid having to look up the property by name and can directly check the accessibility. We're also interested in having this mapping to handle some edge cases in the typed properties implementation.
And cache it in opcache.
nikic
commented
Oct 10, 2018
I just noticed a new issue (again, also existing prior to this patch): <?phpclass Test {
private$prop = "Test";
functionrun() {
foreach ($thisas$k => $v) {
echo"$k => $v\n";
}
var_dump(get_object_vars($this));
}
}
class Test2 extends Test {
public$prop = "Test2";
}
(newTest2)->run();This currently prints: So both the private and the public property are shown. The get_object_vars() case returns a corrupted array with duplicate keys. We can't simply assume that because a property is public that is visible from the current scope, because there might be a more specific private property. |
I have fixed the above issue with 4d5d779. It was actually throwing an assertion failure on master. However, @bwoebi pointed out another, larger problem: <?phpclass Test {
private$prop = "Test";
functionrun() {
foreach ($thisas$k => $v) {
echo"$k => $v\n";
}
var_dump(get_object_vars($this));
}
}
class Test2 extends Test {
}
$test2 = newTest2;
$test2->prop = "Test2";
$test2->run();This also currently prints: In this case we would have to hide the dynamic property, as the private one is in scope. This goes against our usual assumption that dynamic properties are always visible. This means we must perform visibility checks for dynamic properties as well :( This is maybe less terrible than it sounds, because we can short-circuit this for the case where the class defines no properties, so at least |
php-pulls
commented
Oct 12, 2018
Comment on behalf of petk at php.net: Labelling |
Taken from PR php#3573, minus the foreach/iteration parts.
nikic
commented
Jan 7, 2019
I've included this in the typed properties patch at #3313 (without the foreach/iteration changes -- only used for typed props for now). |
Currently there is no efficient way of finding the property_info
which corresponds to a given property slot. This patch implements
such a mechanism, by storing an array of property_infos in offset
order on the class. This structure is lazily initialized when it
is needed, though we could also compute it during inheritance.
This patch only uses it to optimize visibility checks during
foreach (and get_object_vars etc). We avoid having to look up the
property by name and can directly check the accessibility.