Like many PHP programmers I was pleased with the new features that came with PHP 5, and I awaited the release of 5.1, with its wide array of 'improvements', with eager anticipation. Like many I was disappointed that the 5.1 release date seemed to be the subject of one delay after another. Then with new releases of PHP in the 4.4.x and 5.0.x series there started to be complaints that scripts which had run for years were now throwing up errors, that 'backwards compatibility' (known in some quarters as 'BC') was broken. Many sites did not relish the idea of having to spend an unknown amount of time in upgrading their scripts, so they either reverted to the previous working version or, after hearing the horror stories, never upgraded to the new version at all.
Then in various newsgroup posts and blogs I started to hear rumours about the future direction of PHP, and I have to say that I did not like what I heard. I started to read the PHP mailing list for the internals group where the core developers correspond between themselves. These are the people who actually work on the language core itself rather than those who write programs with it, like me. The attitude from some people seemed to be along the lines of:
Now that we've broken BC just a little bit why don't we go all the way and break it completely. We have a golden opportunity to get rid of all that legacy rubbish and make the language cleaner and purer and more up-to-date.
The fact that this would break thousands of scripts running on millions of sites did not seem to phase these people one little bit.
Those people with legacy code that won't run under version 5 can stick with version 4. They will then have plenty of time to rewrite everything 'properly' when version 6 comes out. Perhaps we could even fork the language into two separate branches so that those people with legacy code that they're too lazy to upgrade can still run with a 'dirty' version while the rest of us can work with a cleaner, purer version.
Amongst the suggestions have been:
Get rid of all that procedural rubbish and make everything an object, just like it is in 'proper' languages.
Get rid of function names with underscores (as in function_that_does_something) and replace them with camel caps (as in functionThatDoesSomething) just like it is in 'proper' languages.
Make all function names case-sensitive, just like in 'proper' languages.
Add support for namespaces, just like in 'proper' languages.
Add support for named arguments, just like in 'proper' languages.
Get rid of that ridiculous $this-> construct in classes and replace it with a symbol so that there are fewer characters to type.
Add new function ifsetor so that a particular result can be achieved with fewer keystrokes.
Remove all items marked as deprecated. These shouldn't be used any more, so people that use them have only got themselves to blame.
Remove all function aliases. This is code duplication and a maintenance burden.
Remove {} for string offsets. This can already be done with [], so two methods are unnecessary.
Remove 'ereg' regular expression functions and keep the 'preg' Perl-compatible functions. This is code duplication and a maintenance burden.
Add support for goto. Although the novice programmer may use it to produce spaghetti code, in the hands of an expert it could be useful.
Prevent assigning values to an array unless it has been first initialised with array().
Cause foreach to throw an error if given anything other than an array as input, thus preventing null from being treated as an empty array.
In the remainder of this document the term 'you' is addressed to PHP's core developers, the producers of the language, not the users of the language like me.
If you want PHP to be considered as more than a 'toy' language then you must stop behaving like petulant children. If you want PHP to be accepted into the big league, to earn the reputation of being 'enterprise ready', then you must act like you belong in the big league instead of the local kindergarten.
You are not improving the language, you are killing it. If you are not careful you will end up just like the doctor who said 'The operation was a success, but the patient died'. PHP 5 has been available for 18 months, yet has only been accepted by about 5% of web hosts. Why is this? Simply put, it is the fear of breakages in backwards compatibility. Hosting companies will not upgrade if it means upsetting their customers.
You are small in number, maybe several dozen, but according to the Netcraft statistics there are over 22 million PHP domains out there. That means that you are outnumbered by several 100,000 to 1, so your personal opinions are no more significant than a grain of sand in the desert. The fact that you are unpaid volunteers is irrelevant. It is no excuse for an unprofessional or irresponsible attitude. You volunteered your time to assist the greater PHP community, so if you are unprepared to satisfy the needs of that community you should withdraw.
You are the producers of a product, the PHP language, and we developers are your customers. We in turn use PHP to produce a variety of software applications for our customers. In my many years in the IT industry I have been the customer of many software products such as operating systems, compilers and editing tools, and as a programmer I have been the producer of many applications which have serviced the needs of my customers. In that time I have experienced many upgrades, both as a consumer and a producer, and I can safely say that an upgrade is expected to contain only two things:
Bug fixes.
New features.
Please notice that 'breaking existing features' does NOT appear in that list. The ONLY time it is permissible to break an existing feature is where something is found to be the cause of an error, and the only way to deal with the error is to prevent it happening in the first place. In such circumstances both the cause and effect of the error should be fully documented and explained so that the customer knows exactly what is going on and why. In other words the developers must provide justification for breaking backwards compatibility. Where possible an alternative method should be identified, as in "doing it this way causes so-and-so problem, so we had to prevent it, but doing it in this other way is perfectly safe".
If something is documented then it should work as documented. If it doesn't then it's a bug. It should also continue to be supported ad infinitum. Removing support for a documented feature is simply an indication of laziness or incompetence on the part of the developers. It has been known for some developers to change the documentation instead of changing their code, but as far as I am concerned this is yet another manifestation of laziness or incompetence.
If a user adopts a technique which is not documented then they have no right to complain if it suddenly stops working or behaves differently in a new release. The developer's argument would be that the product works "as documented", so the fact that something undocumented works in a particular way today does not guarantee that it will work in the same way tomorrow.
Note here that the removal of undocumented features can only be justified if it is balanced with the continuation of features which are documented. It would not be fair to have one without the other.
In my long experience of dealing with upgrades, both as a consumer and a producer, may I offer some golden rules that you would be well advised to give serious consideration:
The customer is always right
Customers are valuable. Without customers actually using a product, that product is useless and might as well not exist. If enough customers want a particular enhancement, then it is the developer's job to provide that enhancement. If different customers want different methods to achieve the same result, then it's the developer's job to provide those different methods. It is not acceptable for the developers to say "We're sorry, but we are only prepared to write enough code for one method, so more than one method is out of the question". It is the developer's job to write code to satisfy their users' requirements, not to invent excuses why they shouldn't write code.
One man's meat is another man's poison
The product exists to keep its customers happy, not to keep its developers happy. Providing a solution is the primary concern. Providing an elegantly-coded solution, or a technically pure solution, is secondary. Besides, different developers have a totally different notion of what is, or is not, "technically pure". What is neat to some is nauseating to others. To put it another way, One man's purity is another man's putrefaction. So saying that you want to break backwards compatibility for no other reason than "code purity" is unlikely to win friends among the user community.
If it ain't broke, don't fix it
This saying originated in the original engineering world before it was applied to the creation of software, but it is just as apt regardless of the setting. It means that you should only expend effort where effort needs to be expended. To put it another way, If it doesn't cause a problem it doesn't need a solution. If you not are modifying a piece of code to fix a bug or to add a new feature then what you may actually be doing is introducing a new bug. It is a recognised phenomenon in the non-software engineering world that a significant number of faults occur as a direct result of preventive maintenance (PM). This is a type of maintenance which, instead of being in response to a fault, is scheduled at otherwise quiet times to help prevent faults. Unfortunately the physical act of disturbing a delicate piece of engineering in order to give it a clean-up is also likely to disturb the gremlins. That is why an experienced engineer would rather have a dirty engine that works than a clean engine that doesn't.
Image two software products:
Product A is brilliant in the eyes of the developers, but fails to impress customers.
Product B is brilliant in the eyes of the customers, but developers complain that it is technically "impure".
Which product has more value? Customer perception is much more valuable than developer perception, so building something that satisfies the needs of the users takes priority over building something that pleases the developers. If all software products were delayed until the developers were satisfied that it was technically "pure" I don't think many products would actually be released.
A product is developed for the benefit of its customers, not for the convenience of its developers. Working on a product which is technical crap but which sells like hot cakes is better than working on a product which is technically pure but which no one wants. You may, over a period of time, be able to clear up some of the technical mess, but if you break anything in the eyes of your customers then that is a step too far. Too many breaks and they will drop your product and take their business elsewhere.
As to that list of suggested "fixes", here are some of my personal comments:
When you speak of 'proper' languages you mean 'languages that you are used to'. But why should the syntax of PHP be changed just to suit the preferences of a few individuals? Thousands of developers are happy with the language the way it is, and have been for years. If you really prefer the syntax of 'language X' then I suggest you go and play with 'language X' and leave the rest of us in peace. I have worked with many different 2nd, 3rd and 4th generation languages in my long career, and I've never complained that the syntax in a new language was different from my previous one. It is precisely because of these differences that makes one language stand out from another, or more suited to a particular task, so if you cannot handle the differences then you are, in my humble opinion, in the wrong profession.
Removing deprecated or duplicated functions may sound like a good idea, but if any of those functions are still widely used then they should be left alone. Removing register_globals would be a good idea as this represents a serious security problem, but if a deprecated or duplicated function does not actually cause a problem then it doesn't actually need a solution. Instead of wasting time on unnecessary "clean-up" operations which will achieve nothing but aggravation for existing customers you should instead concentrate your efforts on more important issues. This does of course suppose that you have the brain capacity to recognise what is important and what is not.
Removing function aliases does nothing except annoy users. The fact that a function has two entry points does not mean that the code is duplicated and is therefore a maintenance burden, it just means that the same piece of code can be accessed with more than one function name. I have worked with several languages that incorporate function aliases and it has never caused a problem, either for the developers or the users. If there is no problem then there is no need for a solution.
If it is possible to detect where some application code is wrong and work around it instead of rejecting it completely, then this should be implemented. One of the biggest recent problems has been caused by a 'fix' which rejects the incorrect usage of references. Although this has been done to correct the cause of a memory corruption is actually rejects more than it actually need do. It has been suggested that it may be possible to create a local copy within the function when a ref-to-temp-var is detected at call time, treat it as a by-value argument, and issue an E_NOTICE or E_STRICT instead of E_ERROR. This would then resolve the memory corruption issue without breaking BC. Some developers do not like this idea as they see the implementation as being "messy", that it is the programmer's fault for using references incorrectly. The point is that if a solution is available which will resolve the memory corruption AND not break thousands of existing scripts, then stop arguing and IMPLEMENT IT! The fact that a solution may seem to be "messy" in the minds of a few is irrelevant. It's your job to implement solutions, not problems, so STFU and get on with it!
It could be argued in some quarters that this reference problem is actually YOUR fault for not providing adequate documentation in the first place. By not defining exactly where references can be used, where their use is meaningless, and where their use is actually wrong, you allowed incorrect usage to pass unnoticed for a long period of time. Even worse, by not trapping certain incorrect usage at source you allowed a memory corruption to materialise, then, instead of fixing it with the minimum of impact you promptly broke thousands of scripts. The effect of this has put the reputation of PHP in serious jeopardy and slowed down the migration from version 4 to version 5. I think you should give yourselves a slap on the wrist and promise not to do it again.
The idea that I should have to initialise a variable with array() before using any array functions on it is a stupid idea. The existing code treats a null/false value and an empty array as one and the same thing, and there must be countless lines of code out there in userland which rely on this behaviour. Changing this will not add anything to the language, but it will cause untold scripts to start producing wrong results and thereby alienate a huge portion of the user community. Statically typed languages may insist that a variable's type is set before it can be accessed by functions that will only work on a variable of that type, but dynamically types languages do not. Here is a News Flash, kiddies, PHP is dynamically typed! I do not have to declare a variable as being numeric before using a numeric function on it, I do not have to declare a variable as a string before using a string function on it, and I do not have to declare a variable as an array before using an array function on it. PHP has been specifically designed to work that way, so I suggest you learn to live with it, STFU and move on to more important issues.
Introducing the goto statement is not a good idea. Having worked in COBOL for 16 years I have direct experience of the mess it can create. Although it may be of use in limited circumstances if used wisely, the potential for abuse when used unwisely is just too great. It is not a good idea to fill the language with functions or constructs with which the unwary programmer can shoot himself in the foot. If the damage than something can cause is greater than the benefits it can offer, then on balance it is not worth the effort.
My opinions on the issue of making PHP more case-sensitive, where a word with the same spelling but different case means something totally different, have been moved to a separate document.
Changing existing syntax so that there are fewer characters to type in, supposedly to give a boost to programmer productivity, may actually have the opposite effect. More time is spent in reading code than writing it, and reading code that is littered with symbols instead of meaningful words does not necessarily speed up the reading process. The reader may have to continually pause in order to obtain the meaning of all those obscure symbols, so any time gained in the writing process ends up by being wasted many times over in the reading process. I have worked with some languages that use symbols, and other languages which use proper words, and as far as I am concerned words are far more readable than symbols.
To sum up, here are my Ten Commandments regarding software upgrades:
Don't break backwards compatibility.
Don't mess up the product for 99.9% of users just to provide a "cool" feature requested by 0.1% of users. Some "cool" features can be abused, by both novices and experts alike, to produce a real can of worms.
Don't break backwards compatibility.
If you have to change the way that something behaves then provide a switch (such as a setting in the ini file) so that existing code can still run with the 'old' behaviour instead of producing unexpected results with the 'new' behaviour. Make the 'old' behaviour the default so that those customers who don't want the 'new' behaviour don't get caught out because they forgot to flick the behaviour switch. It is the people who actually want the new behaviour who should be forced to flick the behaviour switch.
Don't break backwards compatibility.
If you cannot introduce new functionality without breaking existing code then consider creating a new set of API's for the new functions. Development (but not bug fixing) on the old API's should be stopped, but existing code using those functions will continue to run without any problem. If someone wants access to the new functionality then they must change their code to use the new API's. Any claim that this causes a maintenance burden is utter rubbish as only the new code should need any maintenance.
Don't break backwards compatibility.
Don't forbid something just because you don't think it should be done that way, or because a function is being used in a way other than originally intended. Unless it causes something to break it doesn't need fixing. You may think that it's a silly thing to do, but the customer wants to do it that way, and the customer is always right. I have seen developers waste time writing code that prevents a function from being used in a certain way even when that usage did not cause any breakages. Trapping imaginary errors is almost as annoying as not trapping real errors. The philosophy should be that everything is legal unless there is a good reason why it should not be so, and not the reverse where everything is illegal unless there is a good reason why it should be.
Don't break backwards compatibility.
Do not remove functionality just because the same result can be achieved by other means. Many languages provide alternate methods to achieve a particular result, and it is up to the customer, not the supplier, to decide which one to use. You may think that having two methods means that one of them is redundant, but if it's being used anywhere IT IS NOT REDUNDANT!
Don't break backwards compatibility. (What? You've never heard of the 11th Commandment?)
One final word. Breaking backwards compatibility is not like breaking a promise, it is more like breaking a leg - very painful, and it puts you out of action for some while. So if you core developers promise not to break backwards compatibility with our favourite language, we, your customers, promise not to break your legs. Deal?