While some people may regard the title of this blog post to be over the top, an insult to the core developers which could have been expressed in a more diplomatic way, I'm afraid that using genteel language would not adequately express what I feel about this particular issue. If the words are true then they should accept them whether they like it or not, or as the saying goes: If the cap fits, wear it. I could have used a more subdued form of expression so as not to upset their delicate sensibilities, such "Their behaviour was sub-optimal", but that would have been so weak and feeble it would have gone unnoticed. Using big-boy words has the effect of grabbing their attention.
The cause of my anger is that I have recently upgraded my PHP version from 8.0 to 8.2 and my code is now disgorging huge volumes of deprecation notices as if it was suffering from a bad case of dysentery. The particular notices in question are:
Passing null to parameter #1 ($string) of type string is deprecated
Passing null to parameter #1 ($num) of type int|float is deprecated
I looked for the source of this decision and found this in the deprecation notices for migrating from 8.0 to 8.1:
Scalar types for built-in functions are nullable by default, this behaviour is deprecated to align with the behaviour of user-defined functions, where scalar types need to be marked as nullable explicitly.
I looked for the source of this horrendous decision and found it in PHP RFC: Deprecate passing null to non-nullable arguments of internal functions:
Internal functions (defined by PHP or PHP extensions) currently silently accept null values for non-nullable arguments in coercive typing mode. This is contrary to the behavior of user-defined functions, which only accept null for nullable arguments. This RFC aims to resolve this inconsistency.
Just because the function signatures in the PHP manual did not indicate that the parameters were nullable does NOT mean that they were always supposed to be non-nullable. At the time the manual was written there was no method of indicating this behaviour in the signature's type hints. This did not change until the release of version 7.1. However, all these functions behaved as if the parameters were nullable, and this was documented in:
Converting to string
String conversion is automatically done in the scope of an expression where a string is needed.
null is always converted to an empty string.
Converting to integer
To explicitly convert a value to int, use either the (int) or (integer) casts. However, in most cases the cast is not needed, since a value will be automatically converted if an operator, function or control structure requires an int argument.
null is always converted to zero (0).
This meant that as soon as the type system had been amended in version 7.1 to allow nullable type hints for scalars then the type hints for all internal functions in the manual could have been amended to make their nullability explicit. Yet the core developers took no action.
The RFC also states the following:
This is contrary to the behavior of user-defined functions, which only accept null for nullable arguments. This RFC aims to resolve this inconsistency.
Considering the fact that the arguments of all internal functions HAVE been nullable for the past 20 years, as stated in the manual, the ONLY inconsistency was the fact that when version 7.1 was released the function signatures in the manual were not updated to explicitly state that they were nullable. It was the manual which became inconsistent with the way that the functions had been behaving for the last 20 years, not the other way around.
After the changes in PHP 8.0, this is the only remaining fundamental difference in behavior between user-defined and internal functions.
This is a blatant misrepresentation of the facts. Before type hinting for scalars was introduced in version 7.0 it was possible for all user-defined functions to have nullable arguments, just like the internal functions had always had. It was just a matter of how they were coded. With the release of version 7.1, which added nullable type hints to the type system, it then became possible to make user-defined functions behave exactly the same as internal functions.
Historically, the reason for this discrepancy is that internal functions have supported a concept of scalar types (bool, int, float, string) long before they were introduced for user-defined functions in PHP 7.0, and the existing implementation silently accepted null values. For the new scalar type declarations introduced in PHP 7.0 an explicit choice was made to not accept null values to non-nullable arguments, but changing the existing behavior of internal functions would have been too disruptive at the time.
The fact that the original implementation silently accepted null values was not an accident, it was a deliberate act on the part of PHP's founders, as documented in RFC: Strict and weak parameter type checking. The logic behind this decision was perfectly reasonable and pragmatic:
The standard behaviour of PHP from day one, being a dynamically and loosely typed language, was to silently coerce any string value into the expected type when used as an argument in any internal function. NULL values from the database would be treated as empty values. This then allowed PHP to happily process all values without the need for any developer to insert extra code to explicitly change a value's type. The only time that an error would occur was when the string value could not be accurately coerced into the relevant type. For example, the string '10 green bottles' contains characters which are not numeric, so that would produce an error at runtime. This is the developer's fault for not doing his job properly. It has been standard practice for as long as I can remember that all data from outside sources be validated before they are process. If this validation detects an error then control should immediately be returned to the user with a suitable error message. This prevents the bad data from either causing a corrupt result or a confusing error message further down the line. This is NOT a fault with PHP's type system.
While not accepting null for a non-nullable argument is perfectly valid stance, this did NOT require changing any internal functions as they had never in the previous 20 years behaved as if their arguments had been non-nullable. The documentation did not show any nullable type hints because type hints in the language did not exist until version 7.0, and it was not until version 7.1 that nullable types were made available. Instead of changing the documentation to become consistent with this long-standing behaviour they changed the functions so that their behaviour matched the documentation - they removed the ability to have nullable arguments. The change made in version 8.1 therefore broke the way in which the language had behaved for the previous 20 years. This fits the description of a Backwards Compatible (BC) break.
I consider that deprecating a feature that has existed in the language since its inception to be a completely insane decision which is going to cause enormous amounts of grief for thousands of developers and millions of websites. According to the W3Techs survey PHP is used on over 77.6% of the world's websites, so that is a HUGE number.
Before PHP came along earlier languages, such as COBOL, were strictly typed for the simple reason that they used predefined structs (also known as records, composite data types or data buffers). All input/output operations required a pre-defined and pre-compiled record structure which identified precisely the type and size of every piece of data that was passed in that operation. Each form/screen had to be built and compiled in order to define all the data items on that screen. Each database access had to define every column used in that access. The application code that dealt with that I/O operation had to use the exact same data structure otherwise the the wrong value would be retrieved and chaos would ensue. The process of defining the record structure for each operation also required that each data item be listed in the correct order. Trying to access a string as an integer, or an integer as a string, would result in corrupt data. If the sending and receiving structures had the data items defined in different orders this would result in corrupt data. Arguments passed into and out of subroutine calls were also structures, so again the structures used by the calling and the called components had to match precisely otherwise this would result in corrupt data.
In my COBOL days I helped ensure that the structures used within each program were always synchronised with the structures used by the forms and the database by creating a program called COPYGEN which would read the structures directly from the forms file or database and write them as text files which could be imported into a copy library. When a program required one of these structures it would read it from the copy library instead of having to be hard-coded by the developer. Thus when any structure changed all that was necessary was to rerun the COPYGEN program and recompile all those programs which referenced that structure. This simple piece of automation cut out a lot of developer-induced program bugs and helped with programmer productivity.
PHP does not use pre-defined and pre-compiled structures which are typed, it uses dynamic arrays which are untyped. These arrays can be regarded as dynamic structures as the contents of an array does not need to be defined before it is filled with data. At runtime values are coerced into the relevant types as and when necessary. When the contents of an HTML form is submitted to a PHP script it appears in the $_POST array. This is an associative array which contains a list of name => value
pairs where the value is always a string. This is because the HTML document does not contain any type information for each of its fields. When data is retrieved from the database the result appears as an indexed array of associative arrays. The first level is indexed by row number, which always starts at zero. Each row is an associative array with a separate field for each item specified in the SELECT query. Again each column of data appears as a string as the SQL output is designed to be sent in human-readable format. Again it is not necessary to define the structure of the array before running the query as the array is built dynamically by the DBMS when the query is executed.
The only different between HTML data and SQL data is for empty values - in the $_POST array they appear as empty strings while in the SQL array they appear as NULLs. This did not matter in PHP 4 as any variable containing an empty string, NULL or FALSE was regarded as being empty()
and was always coerced successfully into an empty value for the relevant type. This standard behavior has now been removed by those idiot core developers, thus proving that they do not understand the roots of PHP and are seeking to change it to suit their own perverse interpretations of how a "proper" language should behave.
Because the structure of an array does not have to be defined before it can be filled with data it provides a dynamic mechanism which is both powerful and flexible for the sending and receiving of data. I can construct methods which send and receive data as single array arguments and these arrays can contain any number of columns from any number of sources - either HTML or SQL - without having to be amended. This is why I use a standard $fieldarray variable as the input and output arguments in my common table methods which are defined in my abstract table class and inherited by every concrete table class. This provides the polymorphism which allows me to access any Model class from any Controller, using that mechanism called Dependency Injection, which contributes directly to the power of my Transaction Patterns and my high rates of productivity.
It would appear that many developers learned about OOP in one of those early languages which used structs and which required strict typing. They assumed that this was the way it should be done, and they cannot adjust their thinking to deal with the new breed of languages which are not compiled and which do not require strict typing. PHP does not use structs which have to be defined for each input/output operation, it uses untyped arrays which are infinitely more flexible. Being dynamic it means that I can define a function with an array argument, such as my $fieldarray, and at runtime I can fill it with any amount of data from any source. I can change the contents of this array at any time without having to modify any method signatures, thus proving that my software is as loosely coupled as it could possibly be. This directly contributes to the increase in polymorphism which is available in my framework, which leads to an increase in the volume of reusable code, which leads to a decrease in the code which I have to write, and this contributes to my high rate of productivity.
This unwarranted BC break now causes every developer to add code to their applications to do manually what used to be done automatically. How can this be called a good idea? How can this be called progress? How can this be called an improvement?
Since it was first released PHP has always been dynamically typed and not statically typed, as well as weakly typed and not strictly typed. This is described in the PHP manual under Types as follows:
PHP is a dynamically typed language, which means that by default there is no need to specify the type of a variable, as this will be determined at runtime. However, it is possible to statically type some aspect of the language [from version 7.0 onwards] via the use of type declarations.
Types restrict the kind of operations that can be performed on them. However, if an expression/variable is used in an operation which its type does not support, PHP will attempt to type juggle the value into a type that supports the operation.
The manual at Converting to string and Converting to Integer had this to say about dealing with variables containing NULL values:
If an expression expects a string then NULL will be converted into '', an empty string.
If an expression expects an int or a float then NULL will be converted into the value zero.
For user-defined functions if any extra type checking was required it was up to the developer to include the necessary code.
For internal functions the manual contained informal type hints on all the parameters, which meant that variables of a different type would be silently juggled into the expected type. When I use the word informal I mean that it used in the manual for documentation purposes, but is not used in the language itself.
Why was this behaviour built into the language? Simply because it was designed to provide a link between HTML forms and relational databases, and both of these support nullable values.
This means that data coming into a PHP script, whether it be from an HTML form or a database, is not typed as everything is either a string or NULL. The fact that PHP could silently deal with this mixture without programmer intervention was one of the reasons why PHP became so popular. This pragmatic approach allowed programmers to write code to get the job done with the minimum of effort. Thus the following code would work:
$quantity = '2'; // this is a string $price = '9.99'; // this is a string $value = $quantity * price; // $result is a number
Notice here that it was not necessary to convert each variable into the correct type before using it in an expression or as an argument in a call to an internal function. This also allowed code such as this:
$price = 9.99; // this is a number $lenth = strlen($price); // this will treat the number as a string and return the value 4
While doing some more research I came across RFC: Strict and weak parameter type checking, written by Lukas Smith and Zeev Suraski in 2009 which states the following:
PHP's type system was designed from the ground up so that scalars auto-convert depending on the context. That feature became an inherent property of the language, and other than a couple of exceptions - the internal type of a scalar value is not exposed to end users. The most important exception is the === operator - however, this operator is used in very specific situations, and obviously only in the context of comparisons. While there are other exceptions (e.g. gettype()) - in the vast majority of scenarios in PHP, scalar types auto-convert to the necessary type depending on the context.
For that reason, developers - even seasoned ones - will feel very comfortable sending the string "123" to a function that semantically expects an integer. If they know how PHP works internally - they rely on the fact the function will auto-convert the type to an integer. If they don't (and many don't) - they don't even think about the fact that their "123" is a string. It's a meaningless implementation detail.
For these reasons - strict type checking is an alien concept to PHP. It goes against PHP's type system by making the implementation detail (zval.type) become much more of a front-stage actor.
In addition, strict type checking puts the burden of validating input on the callers of an API, instead of the API itself. Since typically functions are designed so that they're called numerous times - requiring the user to do necessary conversions on the input before calling the function is counterintuitive and inefficient. It makes much more sense, and it's also much more efficient - to move the conversions to be the responsibility of the called function instead. It's also more likely that the author of the function, the one choosing to use scalar type hints in the first place - would be more knowledgeable about PHP's types than those using his API.
Finally, strict type checking is inconsistent with the way internal (C-based) functions typically behave. For example, strlen(123) returns 3, exactly like strlen('123'). sqrt('9') also return 3, exactly like sqrt(9). Why would userland functions (PHP-based) behave any different?
Proponents of strict type hinting often argue that input coming from end users (forms) should be filtered and sanitized anyway, and that this makes for a great opportunity to do necessary type conversions. While that may be true, it covers a small subset of type checking scenarios. For example, it doesn't cover input coming from 'trusted' sources like a database or files. It also doesn't account for the many developers who are simply unaware of PHP's internal type system, or that presently don't see the need to explicitly do type conversions even if they do sanitize their input. Not to mention those that don't sanitize their input at all...
Note these statements:
PHP's type system was designed from the ground up so that scalars auto-convert depending on the context.
strict type checking is an alien concept to PHP. It goes against PHP's type system by making the implementation detail (zval.type) become much more of a front-stage actor.
strict type checking puts the burden of validating input on the callers of an API, instead of the API itself.
requiring the user to do necessary conversions on the input before calling the function is counterintuitive and inefficient.
strict type checking is inconsistent with the way internal (C-based) functions typically behave.
Anyone who tries to remove an inherent feature of the language cannot be said to be "improving" it in any way, they are destroying it. Anyone who converts an inherent feature of the language into something which is counterintuitive and inefficient should be required to come up with some serious justification. Note that this should exclude such things as "code purity" and "to be consistent with X". A pragmatic approach should always be preferable to one that is dogmatic and pedantic.
The last statement which says that input coming from end users should be filtered and sanitized
has never required each string value to be converted into the correct type. It is quite possible to check that a string value in the $_POST array is consistent with its type in the database WITHOUT actually changing its type. There has never been any rule which says that it should or must be converted, so anyone who says otherwise is overstepping the mark. On the contrary, since its inception the language has been able to use its Type Jugging capabilities to deal automatically with values of different types, which includes NULL. This is a well documented feature that is used by millions of application developers, so its removal would be a huge barrier to sites wanting to upgrade to this version. If they can't upgrade without rewriting their code some may chose to rewrite their code in a different language altogether, one where the developers behave in an adult and professional manner when it comes to maintaining backwards compatibility. Even the Python language has a basic policy for backwards compatibility which states:
incompatibilities should have a large benefit to breakage ratio
This BC break now cause every developer to insert code to do manually what the language used to do automatically. Where I have a numeric value from the database which has no value and therefore appears as NULL I how have to change:
$fieldarray['extended_price'] = $fieldarray['unit_price'] * $fieldarray['quantity'];to
$fieldarray['extended_price'] = (double)$fieldarray['unit_price'] * $fieldarray['quantity'];
As far as I am concerned those extra keystrokes are entirely unnecessary. How can this be classes as an "improvement"?
Below is a history of the changes made to the type system since version 4 (the earliest version that I used):
declare(strict_types=1);
directive with the following explanation in the manual:
By default, PHP will coerce values of the wrong type into the expected scalar type declaration if possible. For example, a function that is given an int for a parameter that expects a string will get a variable of type string.It is possible to enable strict mode on a per-file basis. In strict mode, only a value corresponding exactly to the type declaration will be accepted, otherwise a TypeError will be thrown. The only exception to this rule is that an int value will pass a float type declaration.
Warning Function calls from within internal functions will not be affected by the strict_types declaration.
To enable strict mode, the declare statement is used with the strict_types declaration:
NOTE:
Strict typing applies to function calls made from within the file with strict typing enabled, not to the functions declared within that file. If a file without strict typing enabled makes a call to a function that was defined in a file with strict typing, the caller's preference (coercive typing) will be respected, and the value will be coerced.
This change was subject to PHP RFC: Scalar Type Declarations v5 which contained the following statements:
Summary
These type declarations would behave identically to the existing mechanisms that built-in PHP functions use.
Behaviour of weak type checks
A weakly type-checked call to an extension or built-in PHP function has exactly the same behaviour as it did in previous PHP versions.
Behaviour of strict type checks
These strict type checking rules are used for userland scalar type hints, and for extension and built-in PHP functions.
Why both?
So far, most advocates of scalar type hints have asked for either strict type checking, or weak type checking. Rather than picking one approach or the other, this RFC instead makes weak type checking the default, and adds an optional directive to use strict type checking within a file.
Nullable and union types
Interest has been expressed in a system to allow for union-types: int|float or nullable-types: int?.
As both of these affect more than just scalar typing, both are considered outside of scope for this proposal.
[NOTE: The idea of nullable types was discussed in a different RFC and implemented in version 7.1]
Backward Incompatible Changes
Since the strict type-checking mode is off by default and must be explicitly used, it does not break backwards-compatibility.
Unaffected PHP Functionality
When the strict type-checking mode isn't in use (which is the default), function calls to built-in and extension PHP functions behave identically to previous PHP versions.
Note that this RFC specifically states that type checking for scalars will apply equally to userland, extension and built-in PHP functions. It will be "weak" by default following the same casting rules traditionally used for the parameters of extension and built-in PHP functions, which all had nullable parameters. If "strict" typing is turned ON, using the declare(strict_types=1);
directive, then this will also apply equally to userland, extension and built-in PHP functions. So it's either "weak" for every function, or "strict" for every function.
A single base type declaration can be marked nullable by prefixing the type with a question mark (?). Thus ?T and T|null are identical.
This was subject to this RFC which specifically allowed it for parameters on user-defined functions, although it did not exclude it for internal functions.
This RFC has the effect of implementing strict typing, which enforces type hinting, on all internal functions without using the declare(strict_types = 1);
directive. This to me is wrong. According the manual at Strict typing PHP will, by default, implement "weak" typing in which values of the wrong type will be coerced into the expected scalar type declaration if possible, which means that nulls should not be rejected. This has been the default behaviour since day 1.
This RFC has the effect of overriding the statement included in the earlier PHP RFC: Scalar Type Declarations v5 where it states the following:
Behaviour of weak type checks
A weakly type-checked call to an extension or built-in PHP function has exactly the same behaviour as it did in previous PHP versions.
Behaviour of strict type checks
These strict type checking rules are used for userland scalar type hints, and for extension and built-in PHP functions.
Backward Incompatible Changes
Since the strict type-checking mode is off by default and must be explicitly used, it does not break backwards-compatibility.
Unaffected PHP Functionality
When the strict type-checking mode isn't in use (which is the default), function calls to built-in and extension PHP functions behave identically to previous PHP versions.
Type Declarations - Strict Typing
Warning: Function calls from within internal functions will not be affected by the strict_types declaration.
This means that both forms of type checking, either "weak" or "strict", are supposed to operate on a user-defined function, extension or internal function in the same way at the same time. This RFC has the effect of overriding those statements and implementing "strict" typing for internal functions even though the option has not been turned on.
NOTE: I have just discovered that internal functions that deal with numeric values now throw an exception if the parameter which they are given is not of the correct type. The message that was generated was:
Uncaught exception from TypeError, message = abs(): Argument #1 ($num) must be of type int|float, string given
This again is the exact opposite of what was proposed. Weak type-checking should continue on all internal functions, just as it has done for the past 20+years, UNLESS strict type-checking has been explicitly turned ON - which I never do.
The function signature in the documentation used to read as follows
number abs ( mixed number )
but with version 8 it was changed to:
abs(int|float $num): int|floatThis fatal error has never been mentioned in the backwards incompatible changes for any release. Was this even subject to an RFC, or did some villain sneak it in under the radar hoping that nobody would notice?
In the RFC the logic behind the decision was given as:
This is contrary to the behavior of user-defined functions, which only accept null for nullable arguments. This RFC aims to resolve this inconsistency.
This statement is based on the fact that none of the type hints for arguments of internal functions were marked as nullable in the PHP manual despite them behaving as if they were nullable. The ability to mark any argument as nullable was not available until version 7.1 with the introduction of nullable types, but the function signatures in the PHP manual were never updated to reflect this fact even though version 8.1 did not appear until 5 years later.
Their logic for implementing this massive BC break is therefore seriously flawed. Arguments for user-defined functions have had the option of being marked as either nullable or non-nullable since version 7.1. Without strict typing being enabled this was the standard behaviour for all functions, whether internal or user-defined, since PHP's inception. By choosing to align internal functions with only one of those options the core developers have made a stupid mistake which will now cause untold numbers of userland developers to spend untold hours of effort in fixing code that has run without error for over 20 years.
It was recognised in PHP RFC: Scalar Type Declarations v5, which was implemented in version 7.0, that type checking would apply equally to userland, extension and built-in PHP functions and be either "weak" for all or "strict" for all. It specifically stated the following:
Behaviour of weak type checks
A weakly type-checked call to an extension or built-in PHP function has exactly the same behaviour as it did in previous PHP versions.
The only "inconsistency" which arose at this point was that the informal type hints used in the manual for the parameters of internal functions then became out of step with the actual behaviour of those functions which allowed the parameters to be nullable. The type hinting system was altered to allow nullable types in version 7.1 following the approval of this RFC.
When there is an inconsistency between the documentation and the language there are two ways in which this can be resolved:
Option #1 could have been completed in December 2016 with the minimum of effort to the documentation team, zero effort to the core developers, and zero pain for all userland developers. Instead they waited until November 2021 to inflict option #2 on the world with zero effort on their part but MAXIMUM pain for all userland developers.
Which of these options would a sane person have chosen? Answers on a postcard to .....
Because the core developers chose to fix the wrong inconsistency all they did was create a totally new inconsistency. The way that internal functions work now is totally inconsistent with the main factor which made the language so popular - the fact that it was dynamically/loosely typed but now is not.
All code written prior to version 8.1 will now sh*t its pants like an incontinent child. This release will not improve the language in any way as instead of adding something new and shiny it takes away something old and much-loved, which is sh*tty. This will slow down the adoption rate for the new version to such an extent that the majority of the world's users simply won't be able to afford to rewrite their code. If they DO choose to rewrite it they may as well move to a different language, preferably one which offers backwards compatibility as a feature and not something which can be discarded on a whim.
Backwards compatibility is a feature, not an inconvenience which can be discarded on a whim. It should ALWAYS be maintained unless there is an overwhelming case for its removal. This would include a security issue but would exclude "to be consistent", especially when it concerns being consistent with a user-defined function created by any random developer working with userland code. User-defined functions are the sole responsibility of the developer who created them and have no impact on anyone except those who use his code. Parameters on these functions can easily be switched from non-nullable to nullable with the addition of a single '?' character in front of the parameter's type, so forcing the core functions to be consistent with just one of these userland options seems to me to be the worst possible choice. As the default behaviour of all core functions has always been to accept nullable parameters then why wasn't it possible to change those parameter definitions in the manual to nullable in order to make them consistent with user-defined functions with nullable parameters?
Proposed changes to standard functions in PHP core should always take into consideration the impact they would have on every developer who uses the PHP language, and breaking backwards compatibility should not be allowed unless there is no other option. In this particular case there was another option which involved nothing more complicated than changing the function definitions in core to include the nullable option on the relevant arguments. That's not exactly rocket science, is it!
I have written similar articles on the subject of BC in the past which you can find at:
It has just come to my attention that PHP RFC: NULL Coercion Consistency was raised several years ago, but has not moved beyond the draft stage. It's about time that somebody lit a fire under those idiots to get them moving in the right direction and fix their stupid mistakes.
I started a thread on sitepoint.com to discuss this article, but a moderator closed it prematurely simply because he didn't like what was being said, which meant that I did not have the opportunity to reply to this comment. I am including it here instead.
the advice you are being given by @m_hutley and others have been spot on.As far as I am concerned their "advice" is not worth the toilet paper on which it was written. If I were to follow their "advice" I would not be standing on the shoulders of giants, I would be paddling in the poo of pygmies.
PHP has, for several years now, been moving the language away from its more problematic rootsWhat problematic roots? It was designed from the outset to be dynamically/weakly typed, and programmers like myself have been using it for decades without any problems. If you look at RFC: Strict and weak parameter type checking you will see the following statements:
PHP's type system was designed from the ground up so that scalars auto-convert depending on the context. That feature became an inherent property of the language.Strict type checking is an alien concept to PHP. It goes against PHP's type system by making the implementation detail (zval.type) become much more of a front-stage actor.
In addition, strict type checking puts the burden of validating input on the callers of an API, instead of the API itself. Since typically functions are designed so that they're called numerous times - requiring the user to do necessary conversions on the input before calling the function is counterintuitive and inefficient. It makes much more sense, and it's also much more efficient - to move the conversions to be the responsibility of the called function instead. It's also more likely that the author of the function, the one choosing to use scalar type hints in the first place - would be more knowledgeable about PHP's types than those using his API.
Finally, strict type checking is inconsistent with the way internal (C-based) functions typically behave. For example, strlen(123) returns 3, exactly like strlen('123'). sqrt('9') also return 3, exactly like sqrt(9). Why would userland functions (PHP-based) behave any different?
So you see, the pioneers of PHP made it weakly typed for very good reasons, which include practicality, efficiency and ease of use. They chose pragmatism over dogmatism.
They are "evolving it".Evolving means "growing" not "shrinking", it means "adding to" not "subtracting from", it means "becoming more advanced" not "retarded". The only GOOD reason to remove something from the language is if it no longer works, and weak typing DOES NOT fit into this category.
Evolving can certainly mean taking away some features to increase the usability and enhance the language.How does obliterating PHP's weak typing nature increase its usability? Removing a fundamental feature of the language is decreasing its usability. Evolving does NOT mean removing something that has been in the language since its inception and still works as advertised. The language is being devolved and degraded.
m_hutley came up with the perfect example with the mysql_ functions.That is a rubbish example. The ability to access a MySQL database was not removed from the language, but when MySQL version 4.1 was released it had additional features which required a new interface, so in July 2004 they released an additional "improved" extension. It was then up to the developer to decide which extension they used. Being a competent professional I had designed my framework from the outset to be based on the 3 Tier Architecture which meant that all DBMS access was performed in a single Data Access Object (DAO). In order to accommodate the switch between the old and new MySQL extensions I created a new class to call the new APIs, and the framework would automatically use the "improved" extension if it was loaded. There were NO code changes required by any of my users. The fact that the old mysql extension is no longer available in PHP 8 does not affect me in the least as I had already dealt with its future demise in 2004.
Every language deprecates and removes features as it introduces and changes others.Languages being maintained by professional and competent developers do not break backwards compatibility on a whim. They do not remove working features because a group of dogmatists doesn't like them. They listen to their users, they do not ignore them.
you should NEVER be relying on a language to duck type your intentions as a regular rule.Duck typing was never an accidental feature of the language, it was a fundamental feature that was used by hordes of programmers to good effect over several decades. Relying on a fundamental and well documented feature can never be regarded as poor programming practice.
This leaves the interpreter to "guess" what you want to be done on its contextExactly how much guessing is involved to say that the string "12.34" can be coerced into a number while "10 green bottles" cannot. It's not exactly rocket science, is it? I have been using PHP for 20 years, and it has never made a wrong guess. I also have a standard routine in my framework which will validate all user input to ensure that each value is compatible with the datatype of its column in the database. This does not require any code to be written by the application developer. Note that all data coming from either the browser or the database is presented as an array of strings, and NULL has always been considered to be a valid value in both.
while this can be leveraged in spots, you are leaving yourself open to bugsIt has been my experience that the number of bugs created by weak typing is inversely proportional to the competence of the individual programmer.
in any programming language, you should know your types and be as explicit as possible.That is just a personal preference, not a rule that was carved in stone and handed down from the mountain top. PHP, like all other dynamic languages, was not designed to be strictly typed, so if that is not to your liking you shouldn't be using the language.
I am not saying duck typing is essentially bad, but if you are leaving user input or input from a database to determine what happens in an operation, you are playing with serious fire.I disagree, and so would all the millions of developers who have written successful applications without the crutch of strict typing. I never have to validate data from the database because it could not have been written to the database if it was invalid.
It is half the reason other languages have chosen to be strongly typed to begin with.If you compare a list of languages by type you will see that 40% are strictly typed whereas 60% are dynamically typed. That refutes your claim that dynamically typed languages are losing their popularity.
Do you know of any dynamically typed language that switched to being statically typed? It just doesn't happen. It's up to each programmer to choose a language that supports his preferred programming style. Only a bad programmer chooses the wrong language and then complains about it. That would be as foolish as visiting a Chinese restaurant and then complaining that they don't serve pizza.
The PHP working group communicates and discusses changes regularlyOnly amongst themselves. They never solicit input from the millions of userland developers, the people who actually use the language for a living. They simply don't care what the userland developers think.
we know you are frustrated with having to make a lot of changes for features you think are just wacko or doesn't fit with the spirit of the language.It does not bother me that new features are added to the language provided that I am not forced to use them. I don't use a feature "because it is there" or "because it is fashionable", I only use those features for which I can find a genuine use. To do otherwise would be foolish, as well as a violation of the YAGNI principle.
You will still find out that other languages introduce as many breaking changes regularly.The good languages regard backwards compatibility as a feature, not an obstacle. If anything is removed at all, it is because it no longer works, or has been replaced with a superior version. It is NEVER removed because of a change in fashion. The benefits of any BC break should always outweigh its costs. If a BC break does not have any benefits for the userland developers then it cannot possibly be justified.
I consider this change to be a massive and totally unnecessary break in backwards compatibility. It is gradually changing the language from being dynamically/loosely typed to be statically typed. Since it inception PHP has always worked with input, either from HTML or SQL sources, which contain nothing but string values, plus empty strings and NULLS, and has always adequately coerced these values into the relevant types when used as function arguments. By changing this behaviour the core developers are not improving or enhancing the language, they are gradually ruining it for the millions of developers who have become accustomed to its relaxed and non-strict nature which has contributed to its popularity and ease of use. Those developers who would much prefer to work with a strictly typed language should NOT be using PHP in the first place, and should NOT be allowed to change the language to suit their own personal preferences.
This change now forces me to add unnecessary keystrokes in my code to manually convert these string/NULL values into the expected type when the language used to do it automatically.
I always thought that it was a stupid idea to add strict typing to the language, but as it was supposed to be entirely optional I assumed that all I had to do was avoid the use of thedeclare(strict_types=1);
directive and my code which has run for decades would not be affected. However, those incompetent core developers made a right royal screw up by turning this directive ON for core functions even though I do not want it turned on.
The idea that functions should only accept arguments of the correct type is only relevant if the language was designed from the outset to be statically typed. If the language was NOT designed to be statically typed then that argument does not hold water and should be ignored. Any attempt to force it into the language should be resisted. Any core developer who tries to change the fundamental behaviour of the language should be removed from the core developer team.
A serious problem I see with PHP's current RFC process is that only those developers who can actually make changes to the source code can propose changes and vote on them. As PHP's source code is written in the C language it means that only experienced C developers can become PHP core developers. Unfortunately C operates on different principles to PHP, and those core developers cannot handle the differences and so try to add features to PHP to make it look and feel more like C. This to me is a retrograde step. It is like trying to force an internal combustion engine to behave more like a steam engine.
This means that only those developers who are allowed to vote on changes to the language are those developers who can actually make those changes, and these are the same people who want to change the language to suit their own ideas on how the language SHOULD behave. The number of active core developers is quite small (less than 100) whereas the number of active developers is huge (in the millions). This means that those millions of userland developers whose livelihood depends on producing and maintaining working applications for their paying customers have great difficulty in keeping their versions of PHP up-to-date due to a constant barrage of BC breaks which are totally unnecessary. They are implemented to satisfy the whims of the few and not the genuine needs of the many.
It's about time that changes to the language were put to a proper democratic vote, which involves the community of userland developers. The tyrannical attitude of these elitists who don't care for the opinions of us plebs, who are trampling all over the language with their jackboots, needs to come to an end. A "good enough" language used my millions will always be better than a "perfect" language used by a few purists. If other languages are already deemed to be better than PHP then these saboteurs should switch to one of those languages and leave PHP alone.
To avoid a repetition of this SNAFU I would like the following change made to the RFC process:
The reason that these rules were not originally stated when the RFC process was created was because none of the pioneering developers ever believed that anyone would be stupid enough to break the language. This is what happens when you replace intellectual giants with people of lesser ability.
24 Nov 2024 | Added Typed structures have been superseded by untyped arrays |
09 Mar 2023 | Added Response to Sitepoint post |
04 Mar 2023 | Added Why is strict type checking problematic? |
02 Mar 2023 | Amended Strict Typing is supposed to be optional to include a new complaint. |
This article has been discussed on Reddit where you will see that a large number of people are of the opinion that the pre-8.1 behavior was wrong and simply should not have been allowed in the first place. That is a cock-eyed opinion. Down here in the real world we do not call something wrong unless it causes a problem. If the only "problem" caused by allowing a long-standing feature to continue to exist is to upset the delicate sensibilities of those purists who insist that it should not be allowed, then all I can say is Aw Diddums! These people should stop throwing their toys out of the pram and grow up! Mind you, this could be difficult for pygmies as they have been genetically stunted since birth.