Thank you all for the feedback on the topic of BC breaks in argument
validation https://news-web.php.net/php.internals/126706
I have collected all concerns, prepared an RFC for this change, and I'm
opening discussion on its content:
https://wiki.php.net/rfc/minor-version-compatibility
Since this touches on the broader topic of release policy and BC
expectations, I’d also like to open the door for related improvements.
Rowan raised several valid points that highlight the need for clearer
communication and expectations around minor version changes. If the
community feels it's appropriate, I’m happy to include these suggestions in
the voting. The more clearly BC policy is defined, the less time we’ll need
to spend on debating individual cases in the future.
Rowan’s suggestions included examples like:
Maybe we could work on some criteria that could be applied (and publicised
to users) about what is and isn't allowed in minor versions.
For instance:
Code that already causes fatal behaviour might cause different fatal
behaviour (e.g. throwing an Error instead of raising an E_ERROR)
Code that directly violates documented types might start throwing
TypeError
Code that previously returned null for invalid inputs might start
throwing ValueError
Kind regards,
Jorg
Hey Jorg,
I have collected all concerns, prepared an RFC for this change, and
I'm opening discussion on its content:
https://wiki.php.net/rfc/minor-version-compatibility
Let me address some parts of the RFC:
-
The secondary vote #1 requires the same handling for everything. I
don't think that's a wise choice.
There may be cases where keeping anE_WARNING
(notE_DEPRECATED
though) may be acceptable.
There may be recently (e.g. last minor) introduced APIs, which, by
oversight, accept unexpected inputs. It may be decided that it would be
too much of a compatibility break to "fix" this in a bugfix version.
However, it should be possible to decide to fix this straight ahead in
the next minor, rather than waiting for the next major. Especially for
recently introduced features, having deprecation periods of possibly 4
years, when they were only introduced the year before, is a bit excessive. -
The secondary vote #2 requires that you either select
E_DEPRECATED
or
E_WARNING. That's not right.E_DEPRECATED
may be a precursor to E_WARNING.
There's no silver bullet on what exactly is to be chosen.
E_DEPRECATED
is for something which will change, but is generally not
problematic in existing code.E_WARNING
is for something which may
change and is probably problematic in existing code.
This though means that there will be cases where there's ambiguity.
That's fine. Reach a soft consensus and then go ahead with that.
I don't fundamentally disagree with the attempt to codify something
here, but ultimately the PHP language does and will continue to profit
from some flexibility in these regards.
I think, with the choices, we've actually ended up making in the last 12
years (essentially since PHP 5.5), users haven't been surprised too much.
At least also anecdotally from my experience - upgrading old code is
perfectly fine to do with last minor -> first minor -> last minor -> ...
upgrades.
New code is not fine to do such major jumps. Semantics of code using
brand new features is improved sometimes. Bugs are fixed. Things end up
slightly different. That's fine though. If you want to live on the edge,
that's the price you pay for this. Being able to rectify freshly
introduced mistakes and inaccuracies quickly is important for the health
of the language.
Please, while it's sane sounding, let's not codify too much of
black-and-white policies.
Thank you,
Bob
Hi,
Thank you all for the feedback on the topic of BC breaks in argument
validation https://news-web.php.net/php.internals/126706I have collected all concerns, prepared an RFC for this change, and I'm
opening discussion on its content:
https://wiki.php.net/rfc/minor-version-compatibilitySince this touches on the broader topic of release policy and BC
expectations, I’d also like to open the door for related improvements.
Rowan raised several valid points that highlight the need for clearer
communication and expectations around minor version changes. If the
community feels it's appropriate, I’m happy to include these suggestions in
the voting. The more clearly BC policy is defined, the less time we’ll need
to spend on debating individual cases in the future.Rowan’s suggestions included examples like:
Maybe we could work on some criteria that could be applied (and publicised
to users) about what is and isn't allowed in minor versions.
For instance:
Code that already causes fatal behaviour might cause different fatal
behaviour (e.g. throwing an Error instead of raising an E_ERROR)Code that directly violates documented types might start throwing
TypeErrorCode that previously returned null for invalid inputs might start
throwing ValueError
This looks a bit too generic to me and it might significantly differ based
on use case as Bob noted. I think we should leave some flexibility and
rather add rules for specific issues where we need some defined approach.
In this case it is handling of errors for cases where only constants are
documented.
Kind regards
Jakub
Thank you all for the feedback on the topic of BC breaks in argument validation https://news-web.php.net/php.internals/126706
I have collected all concerns, prepared an RFC for this change, and I'm opening discussion on its content: https://wiki.php.net/rfc/minor-version-compatibility
Since this touches on the broader topic of release policy and BC expectations, I’d also like to open the door for related improvements. Rowan raised several valid points that highlight the need for clearer communication and expectations around minor version changes. If the community feels it's appropriate, I’m happy to include these suggestions in the voting. The more clearly BC policy is defined, the less time we’ll need to spend on debating individual cases in the future.
Rowan’s suggestions included examples like:
Maybe we could work on some criteria that could be applied (and publicised to users) about what is and isn't allowed in minor versions.
For instance:
Code that already causes fatal behaviour might cause different fatal behaviour (e.g. throwing an Error instead of raising an E_ERROR)
Code that directly violates documented types might start throwing TypeError
Code that previously returned null for invalid inputs might start throwing ValueError
I fundamentally reject the concept of this RFC to restrict our ability to do input validation.
Emitting an E_DEPRECATED
for invalid inputs remains utter nonsense.
And this policy would severely impact incremental improvements to the language.
Moreover, I have yet to actually be shown a lack of "consensus" on this issue by the core dev team.
The following PR [1] was opened on the day this RFC was published (April 13), was reviewed and approved by 2 different core developers that have not participated in the previous discussion thread, and merged on the 15th.
This PR checks that the input string does not contain any NUL bytes, and if yes, now throws the standard ValueError.
A similar PR [2] was open by yet another, different, core developer, reviewed, and merged on April 22.
This, to me, indicates a clear consensus within the core dev team that these sorts of BC breaks are accepted and routine.
Let's go back to how this policy would impact incremental improvements to PHP.
And I will take one of your own prior RFCs as an example.
In this RFC, you point to the following PR [3] titled "round(): Validate the rounding mode", which was opened and merged about 2-3 weeks after you announced your RFC "Add 4 new rounding modes to round()
function". [4][5]
That RFC states the following:
Backward Incompatible Changes
None
And this has been the case since the creation of the document by yourself, to the latest edit. [6]
According to the policy you are suggesting, the above statement is just plain false.
Because introducing new modes when the existing ones are not validates is a BC break, because if someone used the value of what would become e.g. PHP_ROUND_AWAY_FROM_ZERO they would have a change in behaviour (as it would stop rounding like PHP_ROUND_HALF_UP).
You could argue that this point is moot as we ended up not introducing new constants and use an enum for the new rounding modes. [7]
However, you were also against removing the newly introduced constants and to have the new rounding mode only be exposed via the new enum. [8]
The only reason you could state that there were no BC breaks in that RFC, was that validating the input mode is something we could do.
Accordingly, if this was not permitted, the only way to add new rounding modes would have to have been to wait for PHP 9.
Something that is completely ridiculous.
Validating the value of an argument is no different from validating the type of an argument passed to a function.
If PHP had a more advanced type system that include dependent types (which are types that depend on the value) then those ValueErrors would be TypeErrors.
And this is not a foreign concept to many people within the PHP community that use static analysis tools, as non-empty-array
, non-zero-int
, positive-int
, non-empty-string
, numeric-string
, and many others are limited cases of dependent types. [9][10]
So attempting to create a policy where somehow introducing TypeErrors is OK but not ValueErrors is completely nonsensical.
I will repeat this once again, but error-ing on invalid inputs entered by the developer is an advantage.
I cannot comprehend the motivation to let users ship buggy code into production, that might end up hard to debug.
We throw Errors on non-existent constants, functions, classes, etc. for a reason.
As such, if this policy does get accepted, I will start to severely reduce my contributions to the project.
As it would be a clear sign to me that what people want from the project is something that I find completely nonsensical and thus I should direct my energy and time to something more inline with my own design beliefs.
Sincerely,
Gina P. Banyard
[1] https://github.com/php/php-src/pull/18320
[2] https://github.com/php/php-src/pull/18365
[3] https://github.com/php/php-src/pull/12252
[4] https://wiki.php.net/rfc/new_rounding_modes_to_round_function
[5] https://externals.io/message/120971
[7] https://wiki.php.net/rfc/correctly_name_the_rounding_mode_and_make_it_an_enum
[8] https://externals.io/message/123472#123486
[9] https://phpstan.org/writing-php-code/phpdoc-types#integer-ranges
[10] https://psalm.dev/docs/annotating_code/type_syntax/array_types/#non-empty-array
Thank you all for the feedback.
I don't fundamentally disagree with the attempt to codify something
here, but ultimately the PHP language does and will continue to profit
from some flexibility in these regards.
@Bob, I agree that flexibility is desired. That's why I would like to have
rather guideline that instruction. It could be achieved with changing MUST
to SHOULD.
This, to me, indicates a clear consensus within the core dev team that
these sorts of BC breaks are accepted and routine.
@Gina, But that's clearly against current policy which clearly states for
both minor and patch versions [1]:
Backward compatibility must be kept
-
Honestly everything comes from lack of clear ownership of the project.
The only thing I wanted to achieve is that my PR (8 months after creation)
and others similar that I wanted to create is merged. First through soft
consensus, and when that failed through RFC. While at the same time similar
PRs are already merged. It's a bit inconsistent right? -
Regarding to your investigation, I don't argue with it. But according to
the CURRENT policy my RFC should be rejected along with many others.
However, this concern was not raised. The next RFC [2] fixing the problem
was also based on the assumption what's the direction of project (moving
into the enums). Similar thing is about namespaces, there is no clear
policy about moving out functions from global space to namespaces. New
contributors are not aware of such tendencies, neither was I.
And I don't think that I'm suitable to proceed with the policy change as I
barely contribute to the project and don't have much experience and
knowledge about all reasons behind past decisions. And if so I'm leaving
this matter to the core developers to decide. I don't care if it's
deprecation, warning, one version prior or the same. I don't want to waste
more time on such discussion. I just want clear, consistent rules that are
respected by everyone.
- Kind regards,
- Jorg
[1] https://wiki.php.net/rfc/releaseprocess
[2]
https://wiki.php.net/rfc/correctly_name_the_rounding_mode_and_make_it_an_enum
Am 27.04.2025 um 20:22 schrieb Gina P. Banyard internals@gpb.moe:
I fundamentally reject the concept of this RFC to restrict our ability to do input validation.
I am sorry but I fail to see how the RFC restrict the ability to do input validation.
Emitting an
E_DEPRECATED
for invalid inputs remains utter nonsense.
I agree that it should most probably be an E_WARNING, not an E_DEPRECATED. Which is a voting option in the RFC.
I will repeat this once again, but error-ing on invalid inputs entered by the developer is an advantage.
I cannot comprehend the motivation to let users ship buggy code into production, that might end up hard to debug.
We throw Errors on non-existent constants, functions, classes, etc. for a reason.
I am not against error-ing on invalid input, and I don't think anyone else is.
It is all about the migration path for existing software and having guidelines for such changes.
Using intermediate warnings before going to an Exception allows updating an installation step-by-step instead of all at once. Which is important both for projects using a lot of composer packages as well as installations where PHP and applications are maintained by different people (e.g. hosting companies).
Case-studies regarding implicitly nullable parameters and the warning phase:
- https://github.com/hybridauth/hybridauth/releases with fixes for PHP 8.4 was released only last week
- https://github.com/grpc/grpc-php still has not released fixes for PHP 8.4
Sure, this is from one minor version to the next and not about invalid argument values and it uses E_DEPRECATED
instead of E_WARNING
but my main points stays the same:
If this would have been done without warning phase then it would be a blocker for upgrading to PHP 8.4, now filtering this warning is enough while the packages are being updated.
And I am of the very strong opinion that the benefits of reducing friction for upgrading to the current PHP version outweighs the costs. Forgetting to change the warning to an Exception can be simply prevented by e.g. a helper function or even a greppable code comment.
As such, if this policy does get accepted, I will start to severely reduce my contributions to the project.
As it would be a clear sign to me that what people want from the project is something that I find completely nonsensical and thus I should direct my energy and time to something more inline with my own design beliefs.
I find it very unfortunate that you are feeling the need to pressure the community in this way as I can assure you that we all want the project to improve even it is sometimes in different ways.
Regards,
- Chris
Am 27.04.2025 um 20:22 schrieb Gina P. Banyard internals@gpb.moe:
I fundamentally reject the concept of this RFC to restrict our ability to do input validation.
I am sorry but I fail to see how the RFC restrict the ability to do input validation.
[...]
I will repeat this once again, but error-ing on invalid inputs entered by the developer is an advantage.
I cannot comprehend the motivation to let users ship buggy code into production, that might end up hard to debug.
We throw Errors on non-existent constants, functions, classes, etc. for a reason.I am not against error-ing on invalid input, and I don't think anyone else is.
It is all about the migration path for existing software and having guidelines for such changes.Using intermediate warnings before going to an Exception allows updating an installation step-by-step instead of all at once. Which is important both for projects using a lot of composer packages as well as installations where PHP and applications are maintained by different people (e.g. hosting companies).
Case-studies regarding implicitly nullable parameters and the warning phase:
- https://github.com/hybridauth/hybridauth/releases with fixes for PHP 8.4 was released only last week
- https://github.com/grpc/grpc-php still has not released fixes for PHP 8.4
Sure, this is from one minor version to the next and not about invalid argument values and it uses
E_DEPRECATED
instead ofE_WARNING
but my main points stays the same:
If this would have been done without warning phase then it would be a blocker for upgrading to PHP 8.4, now filtering this warning is enough while the packages are being updated.
Comparing a core language change to be the same level as throwing a ValueError on invalid inputs of a bundled extension function is a bit of a straw man argument.
The motivation for this policy change is explicitly about input validation.
And I am of the very strong opinion that the benefits of reducing friction for upgrading to the current PHP version outweighs the costs. Forgetting to change the warning to an Exception can be simply prevented by e.g. a helper function or even a greppable code comment.
I am not saying break all the things, however, breaking clearly buggy code is something I consider a feature.
Letting users ship buggy code in production is not something that I find at all reasonable.
And I am looking forward to your suggestion on how to simply implement this for every single unique validation error that we encounter.
As such, if this policy does get accepted, I will start to severely reduce my contributions to the project.
As it would be a clear sign to me that what people want from the project is something that I find completely nonsensical and thus I should direct my energy and time to something more inline with my own design beliefs.I find it very unfortunate that you are feeling the need to pressure the community in this way as I can assure you that we all want the project to improve even it is sometimes in different ways.
I am entitled to my strong opinions as someone that has provided over 700 reviews to php-src PRs and over 800 reviews to doc PRs in 2024, on top of all my own code, documentation, and internal email contributions.
This gives me a very broad overview of the state the whole PHP project is in, and claiming that everything can "just be done at a later date easily" is a completely unrealistic worldview.
Moreover, I know that I am speaking for at least a few other core contributors that don't want to engage more than necessary on this mailing list, considering how draining it can be.
So yes, if the community thinks the way I've been reviewing and contributing to the project is wrong, then severely reducing my contributions is the only reasonable step.
You consider it pressure, I consider it communicating how I feel about contributing to the project, which has already been less enjoyable than before for a while.
Best regards,
Gina P. Banyard
Am 08.05.2025 um 00:36 schrieb Gina P. Banyard internals@gpb.moe:
If this would have been done without warning phase then it would be a blocker for upgrading to PHP 8.4, now filtering this warning is enough while the packages are being updated.
Comparing a core language change to be the same level as throwing a ValueError on invalid inputs of a bundled extension function is a bit of a straw man argument.
The motivation for this policy change is explicitly about input validation.
You are right in principle but from an application / installation maintainers point of view it is irrelevant if an application breaks because old code used a more relaxed language definition (as was the case with implicitly nullable parameters) or invalid arguments (a function might have ignored unknown flags).
I am not saying break all the things, however, breaking clearly buggy code is something I consider a feature.
But now we have the problem of defining "clearly buggy code": If the output of some code was correct even though I gave some unknown flags to a function which were ignored I would call that "should be fixed" but not "clearly buggy".
That's why I'm advocating of treating it in two steps instead of one. That's all I'm saying.
Now there might be cases where you feel like the parameter value is clearly wrong but instead of having to decide that for each and every instance (and people might disagree) I find it easier to err on the delayed-BC-break side.
Letting users ship buggy code in production is not something that I find at all reasonable.
And I am looking forward to your suggestion on how to simply implement this for every single unique validation error that we encounter.
Either do something like
zend_warn_or_throw_exception(E_WARNING, zend_ce_value_error, 80500, "Invalid argument ...", ...);
which automatically either outputs a warning or throw an exception depending on the PHP version or something like
zend_error(E_WARNING, "Invalid argument ...", '...); /* FIXME PHP_VERSION_ID 80500 */
which can be grepped / warned about in CI/CD whenever the PHP version is changed and changed to a zend_throw_exception(...) at that point.
This assumes that it would be possible to define a clear point where the switch from E_WARNING
to ValueError should happen but it seems doable to me without putting a lot of burden on core developers.
Regards,
- Chris
-----Original Message-----
You consider it pressure, I consider it communicating how I feel about
contributing to the project, which has already been less enjoyable than before
for a while.Best regards,
Gina P. Banyard
Just a quick note, your contributions to the project are greatly appreciated by those of us who use the software. This probably isn't outright stated enough. I can understand how the bikeshedding and over-discussion of minutiae can get tedious, just remember there are a largely-silent majority of us out here who are impressed at the direction the language has taken as of late.
-Jeff