Hi, This is the 2nd of two exchanges that occurred off-list that Stas and I would like to put back on-list.
Greg === Stanislav Malyshev wrote: > > Hi! > > >> >> Basically, the patch does 2 things >> >> >> >> 1) resolution order is changed to: >> >> >> >> foo.php: >> >> $a = new foo(); >> >> a) does namespace::foo class exist? >> >> b) try to autoload namespace::foo >> >> c) try to locate internal class ::foo >> >> >> >> 2) if internal class ::foo is found, then cache this information so that >> >> if another reference to the foo class occurs in foo.php, resolution >> >> short circuits to: >> >> a) use internal class ::foo >> >> >> >> This second point is why the slowdown went from ridiculous to slight. > > > > OK, now I understand better what it does, thanks. Do I understand > > right that the caching is in runtime, when the class access opcode is > > executed (since you couldn't autoload in compile time)? If so, how > > long the cache entry is kept there? I.e. if I have execution path that > > goes to file A, then B, then A again, then C, then B, etc. and then > > unroll the stack back - do I store all results for second entrance > > into A? Is it per-op-array (since we don't have per-file data > > structure AFAIK)? What happens if include path (or autoloader) > > changes, so that the class name that could not be loaded before can be > > loaded now - e.g. application adds plugin definitions, etc. - will it > > be ensured that autoloading is never attempted again for the same > > class? What happens if somebody loads that namespace::foo class > > manually (with require) - will the old resolution hold or the new one > > apply? > > > > Also I note that even if the cache stores all resolutions for all > > internal classes times all namespaces, it will still require at least > > one exhaustive autoload search per internal class per op-array - or > > per file, if you somehow find a way to store cache per-file in > > runtime, and these can not be eliminated with bytecode caching, unlike > > all other filesystem accesses. Hi, The caching is at runtime. Basically, it's in executor_globals, and so is not linked to any opcode array (I couldn't figure out any other globally accessible storage location). It works like an associative array. If file X.php loads XMLReader in namespace namespacename, it creates this entry: array( 'X.php\0namespacename::XMLReader' => {class entry for XMLReader} ); So that the next time we reach X.php and the XMLReader class, it sees this entry, and does not attempt autoload. As for your questions about include_path/autoload, I had not added this to the patch, but the easy solution is to clean the hash on include_path change, or autoload change. I assume this code would break with the patch: sneakyreader.php: <?php namespace foo; class XMLReader {} ?> main.php: <?php namespace foo; $a = new XMLReader; // loads ::XMLReader include 'sneakyreader.php'; $a = new XMLReader; // still loads ::XMLReader ?> Whereas with the current behavior, it would instead instantiate foo::XMLReader on the second access. However, this is definitely a wtf situation - the exact same looking line of code would load a different class name entirely depending on what was included. The cache does not eliminate the first autoload per-file. I'm sure there are other issues to work out, but this should give a better idea of what I am trying to do. As for your question of whether to simply error out if foo::XMLReader doesn't exist (in the main.php example above), this also would be acceptable for classes, but not for functions, as the ratio of user-defined to internal functions in any source code example is 1:many, many. However, we don't autoload functions or constants, so load ordr is an absolute, much as it was for classes in PHP 4 before autoload was introduced. It is not an easy problem to solve, but we do need to solve it prior to the next release. Should we take this back on-list? Greg -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php