List of possible changes, updates, additions for PHP 6
wiki.php.net
wiki.php.net
Passing function names around as strings is, of course, a hideous consequence of using separate namespaces for functions (foo) and variables ($foo), so it's at least understandable.
Having to explicitly list a function's free variables with "use" is a hideous consequence of not having lexical scope from the start, so again it's understandable.
What I don't understand is why functions aren't first-class in PHP's parser. For example, the parser doesn't know that functions may be returned from other functions:
$foo = function() { return function() { echo "Hello;" }; };
$foo()(); // Parse error
Instead we have to perform some indirection like this: call_user_func($foo());
Or like this: $bar = $foo();
$bar();
Likewise, the parser doesn't realise that functions may be stored in objects: $baz = new stdClass;
$baz->quux = $foo();
$baz->quux(); // Error, no such method
Again, we have to add an indirection: call_user_func($baz->quux);
Or $foobar = $bar->quux;
$foobar();
Named functions can't be closures, even though we can declare them anywhere, presumably for historical reasons, ie. this is a syntax error: function foo($bar) {
function baz() use ($bar) {
echo $bar;
}
}
Another example of making it unnecessarily hard to use functions is iterable objects, which can only be iterated via foreach loops (ie. there is no way to map, reduce or filter them).Of course, I could also complain about no tail-call optimisation, functions not being curried, etc. but those aren't PHP-specific since very few scripting languages seem to get them right for some reason :(
No, it's a clear avoidance of the problems of the Javascript lexical scope. Yes, it'd be nice to have that "for free", but there's far worse that could happen if you had free access to all variables. The GC complexity alone would outweigh the benefit.
> Likewise, the parser doesn't realise that functions may be stored in objects:
A contrived example actually. First, the interpreter only interprets "$foo->quux()" as a method call on a non-existent method. You are not accessing a property of the object, ever, through a method call like that. Instead, you have the option to implement __call.
class foo {
public $quux;
public function __call($method, $args) {
if (property_exists($this, $method) && is_callable($this->$method)) {
return call_user_func_array($this->$method, $args);
}
}
}
$foo = new foo;
$foo->quux = function () { echo 'hello'; };
$foo->quux();
Changing this behavior could single-handedly break compatibility with all libraries making use of __get/__call methods. It could have been implemented, yes, and probably should have been. However, most people using PHP aren't throwing closures on an object (the closure won't have access to $this scope till 5.4 or later, you know) and expecting them to work like a method.I may address the other points later, but I'm pretty sure that if you'd take a look and try writing idiomatic PHP you'd find it easier than assuming that your idioms from other languages will work directly and without modification.
Do you mean problems with the way Javascript implements lexical scope (no "let" blocks until recently, hoisting, global-by-default, etc.) or problems with lexical scope in general? Lexical scope's been around since at least ALGOL60, but really started to shine in Scheme.
I agree that there's a tradeoff for GC, and as I said it's understandable why "use" acts the way it does, since lexical scope wasn't in there from the start (where it could have informed other scoping policies).
> A contrived example actually.
I agree, but it's contrived precisely because PHP's OO and functional features don't play well together, so everybody's learned not to do it.
> First, the interpreter only interprets "$foo->quux()" as a method call on a non-existent method. You are not accessing a property of the object, ever, through a method call like that.
That's exactly my point! :)
> Instead, you have the option to implement __call.
Yes, this is a decent workaround for a self-contained library/app/etc. but it shouldn't really be necessary.
> Changing this behavior could single-handedly break compatibility with all libraries making use of __get/__call methods.
That's an issue, but I don't think it would be as calamatous as you say :) It would mainly alter behaviour for those who are putting functions in their objects, but as you say that's not commonly done!
> However, most people using PHP aren't throwing closures on an object (the closure won't have access to $this scope till 5.4 or later, you know) and expecting them to work like a method.
I wasn't saying that a function property should act like a method semantically (ie. be called with an implicit $this argument), only that it should be possible to call it like a method syntactically, ie. the syntax "A(B)" should call "A" with arguments "B". Note that it's not just functions; quux could be anything callable.
> I'm pretty sure that if you'd take a look and try writing idiomatic PHP you'd find it easier than assuming that your idioms from other languages will work directly and without modification.
I've been writing PHP since 4.2, so I'm perfectly aware of what does and does not work. I'm pointing out what could work, and make PHP much nicer. Sticking to standard practice is a good idea when writing libraries and applications, but is stifling when brainstorming for a new version of PHP.
My problem with idiomatic PHP is that it's usually incredibly verbose, usually because everything's been collapsed down to be first-order, which leads to boilerplate (eg. repeated build-up and tear-down code) and copypasta ("multiply_all_foos" and "sum_all_foos" which are the same except for the operator, or "Foo->multiply" and "Foo->sum" if you prefer). A few higher-order functions, like function composition and partial application, can cut down this bloat tremendously. It's just jarring when this bumps into a completely unnecessary PHP quirk, like having to put "call_user_func" all over the place ;)
In general. It's powerful to be able to reach out of your immediate scope to access something outside it, but then everything from the defining scope must be retained for later. Because of variable variables, which can be either wickedly difficult to debug or incredibly handy, virtually anything from the defining scope could be accessed in a way the interpreter couldn't predict.
In some ways, I can already see the mess that could ensue. Which is precisely I appreciated the "use ()" syntax.
> I wasn't saying that a function property should act like a method semantically (ie. be called with an implicit $this argument), only that it should be possible to call it like a method syntactically, ie. the syntax "A(B)" should call "A" with arguments "B". Note that it's not just functions; quux could be anything callable.
I guess I can see the value in that. However, that leads to ambiguity during debugging, especially if you've included a dependency and haven't thoroughly vetted it. In that case, you need some XDebug magic to know if $foo->quux was a closure, callable array or string, invoke-able object, or a method. Then you need to determine its call semantics, etc.
I don't think "anything callable" is appropriate. But I do think anonymous functions, closures, and invoke-able objects are. You could then make strings and arrays invokable by wrapping them in a class, but without trying to execute an erroneous string or array.
> I'm pointing out what could work, and make PHP much nicer.
Yeah, your suggestions could work. Whether it would make PHP better or worse depends on the programmer, and the change's second-order effects on how the object model works. But I'm skeptical of its benefit. It would probably wind up muddying the execution logic till at least 1 patch level further. I'd have to see some real-world examples of how this would be useful to fully convince me.
Call me paranoid if you wish, but I wouldn't want a novice programmer stumbling on that change by accident. I can already envision the spaghetti they'd use it to write, then we'd have to come bail them out. ;)
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).
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.
Most PHP programmers seem to have given up and resorted to using echo for debugging.
It's also something you only have to do once, on your development box. So I don't really consider that a hurdle.
The PHP experience is absolutely horrible compared to those of Java, Python, the .NET languages, and even to those of C, C++ and Objective-C.
Take Java, for example. Debugging works seamlessly in pretty much every major Java IDE, including the free ones, on pretty much every platform used for Java development. This has been the case for a decade now, if not longer. It takes basically no effort to start debugging Java code.
The .NET experience is even better, although more limited in terms of tooling. Debugging is stupidly simple and very efficient when using C# and Visual Studio. Again, it has been like this for many years now.
PHP needs to get its act together so that debugging is at least as simple as it is when using those other languages and runtimes. Anything less is just plain unacceptable today.
While installing XDebug may be no rocket-science, I've encountered too many situations that it just didn't work reliably, causing developers to revert to nasty var_dumps() for debugging.
• break at the first line in a script (very annoying when you have to debug something very deep)
• generate tracing logs (horrible to read but the best debugger replacement I had at the time)
• generate profiling logs (very helpful)
I never managed to get arbitrary breakpoints to work so I basically resorted to either traces or var_dump.
From there, some libraries like ezpublish will cause all sort of problems with xdebug depending on where you put the breakpoint (it might be due to the number of recursive call or stack depth), and you'd really want to enable or disable debugging case by case, from your IDE ideally.
Then debugging on a non dev server means installing a new package, configuring it and disable it afterwards just in case it has ill adverse effects.
Then some eclipse pdt versions were stuck when using xdebug on some configs.
Overall it works, but in practice, there's not enough cases IMO where step by step debugging is valuable enough to bother dealing with the not so exceptional weird things.
Which IDE do you use? Granted, most of my issues come from the IDE vendor's browser extension, which only triggers debugging when there's an 'R' in the month... which is highly frustrating.
Yes, how dare these people use their own alphabet.
Also, you should note the recommendation I quote is not about adding the ability to use non latin alphabet, this is about removing that ability. It's been there for over a decade and I don't see that rendering libraries developers brainless, so I would say your point doesn't apply.
Maybe PHP6 could be a complete cleanup. And maybe the focus shouldn't be on backward compatibility but on running <6 and 6 side by side.
- Logs usage of old or (to-be) deprecated functionality
- Provides deprecated functionality so that existing code doesn't break
This way;
- The PHP API can finally be cleaned up (please, also move those old functions to a separate section in the documentation)
- Older code can still run, but enabling the 'migration/compatibility' plug-in (should be possible to enable/disable this per site, not for the whole server at once)
- Developers are informed that their code uses deprecated functionality, giving them time to migrate code.
Although this approach is comparable to the E_STRICT flag, it is going one step further, in that the deprecated functions are actually removed from the core, and must be manually enabled/added via an optional plugin.
Reorganising the documentation is an important part of this; cleaning up the old stuff will make PHP less confusing (should I use 'implode()' or 'join()'?), and will silently guide new developers away from the old stuff.
On a final note; if this approach allows hosting-providers to upgrade PHP without breaking their client's code, adoption rate of newer PHP versions will probably be faster as well!
The big thing with PHPv5 was not just having to migrate code, but even at the time v4 was no longer supported and v5 had been out for years in benchmarks v4 was still 20-30% faster then v5.
v5 to v6 could be a similarly smaller scale migration. The number of backwards incompatible changes in 4 to 5 wasn't long:
http://www.php.net/manual/en/migration5.incompatible.php
Slashdot thread from the time with some details on the resistance:
http://beta.slashdot.org/story/87591
Migrating from v3 to v4 was also a backwards incompatible leap:
http://www.physnet.uni-hamburg.de/physnet/php/migration4.htm...
So the PHP project has pulled it off twice already, perhaps they don't get enough credit for that.
Individuals and organizations with extensive Python 2.x software systems have been able to continue using those with no problems.
Development has been able to continue on Python 3.x without needing to worry about backward compatibility with Python 2.x. It is a cleaner language, in many ways.
Over time, we have indeed seen libraries, frameworks and users migrate from 2.x to 3.x as it benefits them. It's not something that's forced on them, causing disruption and anger.
And so we've gradually seen Python 3.x starting to become more and more adopted, while Python 2.x slowly fades away. It's a non-disruptive, steady transition.
If you want to talk about a real fiasco, Perl 6 is a much better example. Having no truly usable implementation after nearly 15 years, and thus basically no adoption, does qualify as a disaster in every sense.
P.S. But from close-up, it's the think-tank and test-bed of potential Perl 5 upgrades. Even if Perl 6 never ships, it's contributed tons of shipping code for Perl 5. Yes, it's hard to understand that from a distance, and it's not a PR dream, but oh well.
I question this claim. Perhaps it's true of some syntactic features (`say` comes to mind as do some proposals for function signatures), but the semantics rarely translate over well (consider smartmatch). If you squint and tilt your head you can claim that Moose is an example of a feature designed in one language and implemented in another, but Moose is more an exercise in language/feature syncretism than it is porting something complete in implementation or design to Perl 5.
One of the problems with Python is that they almost encouraged writing code in 2 and porting it to 3. Also: Python 3 is almost a complete different language.
It would be the same when PHP6 would use a + as string concatenation. Such changes would turn it into a complete different language.
Somebody who has used both will notice that Python 3 is syntactically and semantically almost identical to Python 2 in most respects. The main differences are in terms of removing redundancy, removing outdated features and functionality, increasing consistency, vastly improved Unicode support, and standard library improvements.
A developer with Python 2 experience should be able to pick up Python 3 in about 30 minutes, at the most. That's not what we'd expect were Python 3 "almost a complete different language".
If we could get on the same page what the new naming conventions and parameter orders are supposed to be, we could start to use a shim file on 5.x to prepare for 6.x.
Would be great if PHP.net and HHVM (Facebook's HipHopPHP) would go on in the same direction (somehow).
So honest question, what if somebody forked php and made those simple changes, how many people would switch?
I would without hesitation.
But then at some point you no longer have PHP you may have something which is close enough to an existing language that just switching to it becomes a more palatable option.
So no, I'd benefit the most with a cleaner syntax than with cooking unicorns in fairy sauce. And I believe 80% of casual programmers agree with me.
Pareto wins.
You can get quite good at doing that, of course, and it's even a useful professional skill, there being so much PHP code in the world, and most of it awful. But doing so does not make you a better programmer, because at best it teaches you nothing useful about how to use less programmer-hostile languages, and at worst it inculcates habits which will prove actively harmful in any later effort to develop skills in such languages.
That you are unable to appreciate this qualitative distinction does nothing to erase its existence, but it does provide an excellent example of the conceptual deficiencies which result from a PHP-centric perspective on programming -- even something as trivial as proper first-class functions you dismiss as "cooking unicorns in fairy sauce", and since PHP doesn't have them, how would you know otherwise?
Whether you choose to address these deficits in your education is, of course, entirely your lookout. I'm just here to point out that they exist. You're free to argue otherwise, should you so choose, but you'll be wrong to do so; I speak here from experience gained in working with people who similarly mistook PHP for a worthwhile general-purpose web development language, who began their programming careers by specializing in it, and who in so doing unwittingly stunted their professional growth in precisely the manner I describe. Some overcame it, and matured into truly professional programmers with whom it was a pleasure to work; some did not, and most of those, as far as I've been able to keep track, eventually drifted out of the field entirely. All, having been seduced by that syphilitic temptress of innocents we call PHP, suffered unduly as a result. (I'd have been among them myself if not for early exposure to Perl, which for all its warts is a thousand times preferable to PHP; having cut my teeth on a language which is merely bad, I was equipped in my first encounter with PHP to recognize the legendarily awful when I saw it.)
It's for reasons like these that, to borrow a quote from the UNIX-HATERS Handbook, "I'm rather surprised that [Rasmus Lerdorf] is still walking around alive"; indeed, long may he continue to do so, for if there's a special hell for programmers, then in its frozen ninth circle there must surely be a waiting hole in the ice with his name carved around the edge -- or, just possibly, a throne.
I understand your grievances with PHP's semantic issues, and I can appreciate that PHP's lack of support for newer, common language paradigms inhibits growth in professional development.
But you replied to a guy who starts his comment with "As a hobbyist". Most of what PHP is used for is for small web development projects that in no way need optional strong typing and full functional support.
At the beginning of your comment you say that if PHP is your only programming language than this deficit leaves you at a disadvantage. Well no shit! There's no silver bullet language that can do everything for everyone 100% of the time. In one breath you lambaste using PHP as your only language; in another you identify that PHP's lack of support for x, y, and z cause the developer to stagnate in learning new things. It seems you condemn using PHP for everything, and then are upset that it can't do everything!
To this I would say use the right tool for the job.
Small web development projects, as you say, do not require strong typing, first-class functions, &c. But they certainly can in many cases be improved by these capabilities, and, in any case, few languages which offer them outright require their use; meanwhile, a language which either fails entirely to offer them, or worse offers a broken, awful version of such functionality to newbies who are not equipped to recognize such enormities and are thus vulnerable to the fallacy that that's how such things are and should be done everywhere, is one which can inflict enormous harm on people who frankly don't know enough yet to look out for themselves -- precisely the sort of people, in other words, which PHP so successfully attracts, through its presentation as the right tool for every web-facing job.
Perhaps you mistook my colorful phrase, "that syphilitic temptress of innocents", for mere hyperbole, and failed to recognize it as the precise, if metaphorical, description which it is. If you have so mistaken me, then I hope this comment helps to clear up the matter somewhat.
The internet is such a wonderful place where we start a fight with someone we don't know if it's a dog with a keyboard or a guy with 25 yrs programming experience with fluency in 22 programming languages.
But what do I know? I am just a hobbyist.
;-)
Utf is not Unicode
https://enjoydoingitwrong.wordpress.com/2009/06/22/unicode-i...
Assuming it somehow works.
I mean who in 2014 is going to start a new project in PHP apart from people that can't be bothered to learn something else ?
People who refrain from having the standard knee-jerk "lol php is bad" reaction whenever it's being mentioned. Of course the language has its warts and pitfalls, but then again, most languages do, and it's a fairly usable tool for a fair amount of jobs.
Care to show me a language with the same adoption rate (especially among hosters, which is something a lot of web devs simply have to keep in mind), ease of getting a project from zero to gone live?
[0]: Strangle Loop 2013: Keith Adams, Facebook: Taking PHP Seriously https://raw.github.com/strangeloop/StrangeLoop2013/master/sl...
[1]: CUFP 2013: Julien Verlaguet, Facebook: Analyzing PHP statically https://www.youtube.com/watch?v=gKWNjFagR9k
[2]: HHVM and Hack – Can We Expect Them to Replace PHP? http://www.sitepoint.com/hhvm-hack-part-1/
http://pypi.python.org/ - 40,037 packages
http://rubygems.org/ - 70,678 packages
http://www.cpan.org/ - 129,447 packages
http://packagist.org - 24,244 packages
There's a lot of open source code out there for all major languages. And, based on the canonical package indexes, a lot less for PHP than the other main contenders in the OSS web-ready scripting space (although, obviously, PHP is very domain-specific compared to the others I've listed, so the comparison is not completely fair - even with that caveat, however, I would expect Perl and Ruby to have PHP licked).
There are compelling reasons to use PHP - omnipresence, ease of deployment - but this isn't one of them.
https://getcomposer.org/doc/05-repositories.md#types
Though I'd agree it is still a weak argument in favor of PHP.