Stan Vassilev | FM wrote: > Hi, > > I'd like to nudge the discussion back to issues with the resolution > rules that we're discovering :) > The actual char(s) used can only be mildly annoying to some (at worst), > compared. > > Can we please agree on those (or explain why you'd not): > > 1) functions, constants and classes should use the same resolution > rules. Making special cases just for some of them, or just for user or > just internal ones will lead to confusion.
I have to agree. In fact, there is a simple and elegant solution to the problem that involves augmenting Jessie's patch to include a more helpful error message on class/function not found, and a simple 51-line PHP script for converting non-namespaced to namespaced code. With these two things, I think we could safely change the name resolution in PHP. > 2) can someone please explain why is it useful to override internal > function inside a namespace. Isn't it better to explicitly refer to > global functions as global, which would allow compile-time resolution in > a lot more cases than now. The reasoning behind this decision that I was given by Dmitry and Stanislav was 2-fold. 1) Currently, the lookup order is optimized for internal functions/classes [more detail below] 2) migrating existing code to namespaces will require much more work if all internal functions/classes must be prefixed with :: or "used" to be avialable Detail: 1) Currently the lookup order is optimized for internal functions/classes. At compile-time, all internal classes/functions exist. However, it is possible that not all userspace functions/classes exist yet. As such, if a T_STRING is encountered, here is how the resolution works currently in the worst case (roughly, in pseudo-code): => is it an internal function/class? if so, use it => does it exist in the current namespace? if so use it => otherwise, mark it for runtime resolution => run code => when we reach this opcode, resolve the function In the best case: => is it an internal function/class? use it However, changing this to allow resolving always to the current namespace would change this to: worst case: => does it exist in the current namespace? if so use it => otherwise, mark it for runtime resolution => run code => when we reach this opcode, resolve the function best case: => does it exist in the current namespace? if so use it This results in a fatal error for all internal functions/classes. The error message for a non-existing class/function should at least hint that a use statement is needed, an element missing from Jessie's patch. In any case, #1 proves to be false, as adding a "use" clause for each internal function/class is no performance hit at all. 2) migrating existing code to namespaces will require more work if all internal functions/classes must be prefixed with :: or "used" As a test, I tried adding a namespace declaration to the top of one of PEAR's larger file, and then ran it with PHP 5.3 and the patch. To my (initial) surprise, it ran without error. On further investigation, I realized why this is so - none of the internal functions/classes were actually resolved, all of them were delayed until runtime, and none were actually executed. What this means is that by adding a namespace declaration, it is quite possible that your code will execute happily until it suddenly encounters a function/class you forgot to "use" or prefix with ::. Fortunately, I just wrote a simple namespace conversion script that solves this problem decisively. The eventual script should be checked over for missing userspace class/functions, as only internal class/functions will be "use"d. Here it is: <?php namespace NSParser; class Parser { protected $tokens; protected $i = -1; protected $classes = array(); protected $functions = array(); protected $use = array(); protected $ret; function __construct($path, $namespace) { $classes = ::get_declared_classes(); $classes = ::array_merge($classes, ::get_declared_interfaces()); $this->classes = ::array_flip($classes); unset($this->classes['NSParser::Parser']); $functions = ::get_defined_functions(); $this->functions = ::array_flip($functions['internal']); if (@::is_file($path)) { $path = ::file_get_contents($path); } $this->tokens = ::token_get_all($path); foreach ($this->tokens as &$token) { if (!::is_array($token)) { $token = array(::ord($token), $token); } } $ret = "<?php\nnamespace " . $namespace . ";\n"; do { if ($this->tokens[$this->i][0] == T_STRING) { if (isset($this->classes[$this->tokens[$this->i][1]])) { $this->use[$this->tokens[$this->i][1]] = 1; } if (isset($this->functions[$this->tokens[$this->i][1]])) { $this->use[$this->tokens[$this->i][1]] = 1; } } } while (++$this->i < ::count($this->tokens)); foreach ($this->use as $name => $unused) { $ret .= "use ::$name;\n"; } $ret .= "?>" . $path; $this->ret = $ret; } function __toString() { return $this->ret; } } ?> Greg -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php