5 ms·
You're right that the parser would benefit from some more work to make edge cases like $foo()() work correctly. It'd be the single most important feature for a
by Udo 13y ago
You're right that the parser would benefit from some more work to make edge cases like $foo()() work correctly. It'd be the single most important feature for a 6.x version as far as I'm concerned.
- chriswarbo 13y agoIt wouldn't need to be a version 6 feature, since it wouldn't break backwards-compatibility, but it may end up having to wait if that part of the interpreter is particularly gnarly (I've played with PHP's C code and I could see why it may be difficult!). Also, I'd hesitate to call "$foo()()" an 'edge case', since that implies that it's somehow different to any other function call. Making such a distinction is exactly what PHP got wrong here, ie. the parser should allow any expression to be called as a function, including other function calls and property lookups. Presumably there are two reasons why this happened: 1) Languages with first-class functions (and lexically-scoped closures) have fewer distinct features than languages without them; ie. functions are no longer distinct from other values (ints, bools, etc.), function names are no longer distinct from variable names (foo vs. $foo), methods are no longer distinct from properties ($foo->bar() could be a method call or a function call), functions and classes begin to overlap (lexical scope competes with instantiation and inheritance for resolving free variables) 2) For performance reasons, when these features were still distinct, they were branched on as early as possible, ie. in the parser. Essentially the problem is that the parser is still making distinctions which first-class functions have unified. The solution is to delay committing to these branches until further down the pipeline, ie. using a generic "expression" token, which "$foo" and "<expression>()" both parse to. The action to take can be resolved at runtime (when the value of the expression is known). In other words, there should be no difference between "<token>(<args>)" and "call_user_func(<token>, <args>)" (except maybe for things like pass-by-reference).
- Udo 13y ago> Making such a distinction is exactly what PHP got wrong here, ie. the parser should allow any expression to be called as a function, including other function calls and property lookups. I didn't imply that I would have done it the same way they did! I merely expressed the feeling that the parser might be implemented in a way that makes this hard to fix without an extensive rewrite. From the parser's perspective this might be an edge case. Admittedly, you know more about PHP internals than I do, but I assumed there would be hurdles in there - otherwise this should have been done years ago. Especially since I expect there is no compatibility downside in making these cases work. Working with PHP I got the same impression as you did, namely that the parser makes certain assumptions about the code structure that causes the result to be more rigid. I agree that ideally the parser should just be agnostic about stuff it can't meaningfully reason about.