Hello PHPeople. I just published the RFC "Deprecation of fallback to root
scope".
It is quite a substantial change, but as you can read in the RFC, can be a
(basically) transparent one.
I'm referring to the possibility to shim it in userland. Essentially, this
would move the feature from core to userland.
I hope you like it. Let me know what you think.
Overall, huge improvement, and also simplifies things quite a lot from a
developer PoV by requiring to add explicit references, so this is 100%
thumbs up.
Marco Pivetta
Hello PHPeople. I just published the RFC "Deprecation of fallback to root
scope".It is quite a substantial change, but as you can read in the RFC, can be a
(basically) transparent one.
I'm referring to the possibility to shim it in userland. Essentially, this
would move the feature from core to userland.I hope you like it. Let me know what you think.
+1
Why should it emit an E_NOTICE
instead of E_DEPRECATED?
The code for the shim should probably use define()
for constants instead of
eval().
Regards, Niklas
No idea, I'm not really sure what's the difference between E_STRICT
and
E_DEPRECATED.
Yeah the shim is just a rough POC (completely forgot that define()
can
define in namespaces).
Nicolas Grekas on twitter also suggested that we should introduce
function_alias() that works like class_alias()
.
With that the shim would be literally a couple of lines long.
No idea, I'm not really sure what's the difference between
E_STRICT
and
E_DEPRECATED.
Yeah the shim is just a rough POC (completely forgot thatdefine()
can
define in namespaces).
Nicolas Grekas on twitter also suggested that we should introduce
function_alias() that works likeclass_alias()
.
With that the shim would be literally a couple of lines long.
From our manual:
E_NOTICE
: Run-time notices. Indicate that the script encountered something that could indicate an error, but could also happen in the normal course of running a script.
E_DEPRECATED: Run-time notices. Enable this to receive warnings about code that will not work in future versions.
E_STRICT: Enable to have PHP suggest changes to your code which will ensure the best interoperability and forward compatibility of your code.
In my opinion we should emit E_STRICT
until we know when the feature
will be removed. At that point we can promote it to E_DEPRECATED
and
specifically cite when it will be removed. In any case, E_NOTICE
does
not seem appropriate.
In my opinion we should emit
E_STRICT
until we know when the feature
will be removed. At that point we can promote it toE_DEPRECATED
and
specifically cite when it will be removed. In any case,E_NOTICE
does
not seem appropriate.
I like the three phase approach. Gives frameworks/libraries/users
ridiculous amounts of time to clean up their code, the route to clean
code is clear and the updates are scriptable (I'll bet PHPCS can do
this already), and at the end, we'll be able to have a better engine
and make certain assumptions in the optimizer.
+1
-Sara
I like the three phase approach. Gives frameworks/libraries/users
ridiculous amounts of time to clean up their code, the route to clean
code is clear and the updates are scriptable (I'll bet PHPCS can do
this already), and at the end, we'll be able to have a better engine
and make certain assumptions in the optimizer.
Yep, PHP-CS-Fixer can do this, see the native_function_invocation option.
I also like the three phase approach and would be excited to see the possibility for function autoloading and further optimizations.
+1
Aaron Piotrowski
I just want to add: vote is not very obvious - non internals people are
getting too excited about this :P Please consider:
People that don't have an IDE that handles the imports automatically, will
be effectively forced to prefix \ to everything, which is really ugly.
But again, prefixing \ is not even the end of the world. I bet that if
fallback to global scope didn't exist from the beginning, we wouldn't care
anymore about prefixing .
PHP has tons of global symbols, it's not like other languages that have
functions organized in classes.
Doing the most basic array and string operations will easily require 4-5
imports, probably more. If all I had to do was use String;
and all the
string functions were available as methods on strings, then it would be
completely fine.
On the other hand, string functions are rarely used, and arrays can be
replaced by oop collections like spl, ds, or even userland ones.
Function autoloading is almost a development feature only, since in a few
years we'll all likely use opcache, which doesn't need autoloading.
2018-02-03 6:27 GMT-02:00 Wes netmo.php@gmail.com:
Hello PHPeople. I just published the RFC "Deprecation of fallback to root
scope".It is quite a substantial change, but as you can read in the RFC, can be a
(basically) transparent one.
I'm referring to the possibility to shim it in userland. Essentially, this
would move the feature from core to userland.I hope you like it. Let me know what you think.
Personally, I'm a +1 on this. I just can't see a 3/2 majority voting yes on
this proposal. But the odds could be a little better with
a "batteries included" RFC offering a tool to automatically update code by
adding the necessary use statements for core functions,
constants, and classes.
Good luck,
Márcio Almada
2018-02-03 14:46 GMT-02:00 Marcio Almada marcio.web2@gmail.com:
2018-02-03 6:27 GMT-02:00 Wes netmo.php@gmail.com:
Hello PHPeople. I just published the RFC "Deprecation of fallback to root
scope".It is quite a substantial change, but as you can read in the RFC, can be a
(basically) transparent one.
I'm referring to the possibility to shim it in userland. Essentially, this
would move the feature from core to userland.I hope you like it. Let me know what you think.
Personally, I'm a +1 on this. I just can't see a 3/2 majority voting yes
on this proposal. But the odds could be a little better with
a "batteries included" RFC offering a tool to automatically update code by
adding the necessary use statements for core functions,
constants, and classes.Good luck,
Márcio Almadahttps://github.com/marcioAlmada
Heh, I meant 2/3 of course :x
Hi!
I hope you like it. Let me know what you think.
I do not see how this makes sense. This RFC claims there's no BC
breakage, while it deprecates one of the most widely used functions of
the language (using unqualified global functions from inside namespaces)
and adds warnings which will break a lot of existing code (and yes,
notice and warning are basically the same).
I do not see how it makes sense to force people to use \strlen
everywhere (since most of the code in large apps uses namespaces now)
for a tiny and rare possibility that someone would override strlen.
Unless I serously misunderstand what this RFC is proposing, I am
absolutely against it and think doing something like this would be
harmful to PHP. Am I missing something here?
Stas Malyshev
smalyshev@gmail.com
Hello PHPeople. I just published the RFC "Deprecation of fallback to
root
scope".It is quite a substantial change, but as you can read in the RFC, can
be a
(basically) transparent one.
I'm referring to the possibility to shim it in userland.
I'm torn on this one. On the one hand, I think in hindsight this is how functions in namespaces should have worked when they were introduced in PHP 6, I mean 5.3. \foo isn't the prettiest syntax, but people soon got used to writing class names that way, including built in ones like \DateTime. It would make function autoloading simpler, lead to less ambiguous code, and make namespaces work consistently across token types, rather than one way for classes and a different way for functions and constants.
On the other hand, the BC break of moving to that now (or committing ourselves to in the future) is significant, and even raising a notice of whatever level could be highly disruptive. A lot of code bases will issue this message hundreds or thousands of times; I wouldn't be surprised if just the code to format the string and pass it to an active error handler might result in a measurable performance impact in some cases. Crucially, the proposed shim can't actually be written yet, so the only way to suppress these notices will be to edit every single source file, which even if perfectly automated creates a lot of noise in version control.
I think some less invasive way would need to be found to make existing code run the same way, without notices, before and after the change. For instance, if you could opt into the old behaviour by writing "import global functions" at the top of a file, or opt into the new behaviour by writing "namespace only Foo", or since autoloading is a key benefit, "namespace Foo with autoload". It wouldn't be ideal, because it means the engine has to support both modes, but it would be far less painful than adding \ into thousands of lines of existing code.
Regards,
--
Rowan Collins
[IMSoP]
Hello PHPeople. I just published the RFC "Deprecation of fallback to root
scope".It is quite a substantial change, but as you can read in the RFC, can be a
(basically) transparent one.
I'm referring to the possibility to shim it in userland. Essentially, this
would move the feature from core to userland.I hope you like it. Let me know what you think.
To get the same benefits (jit and such) wouldn't it be better to introduce
a "use function root;" or similar statement or a declare() to specify this
file imports all root functions?
I am with stas that this will go towards a huge BC break if the deprecation
was acted on at any time in the future. and in addition people will silence
the notices on global error reporting level, because violations would
happen on a massive scale, inclusing the cost of them being raised dragging
performance down. This will be a problem since other notices will go
unnoticed.
Hi!
To get the same benefits (jit and such) wouldn't it be better to introduce
a "use function root;" or similar statement or a declare() to specify this
file imports all root functions?
We already have this right now, and realistically speaking, who wouldn't
do that in their code instead of writing weird \strlen() code? Everybody
would configure their IDEs and so to insert this automatically. So we're
talking about RFC to make people work harder for what they already have
now and then end up in the same place we are already right now.
was acted on at any time in the future. and in addition people will silence
the notices on global error reporting level, because violations would
And note also that we can't silence just this warning. Which means
people would have to silence all warnings, thus making all other
messages useless. This is not a good development and this is not what we
should be training users to do - saying "well, it's a warning, just
silence it" is the worth idea we could have. If we create a warning,
recommendation should be "it's important enough so we call your
attention to it, please deal with it", not "just silence it". If it's OK
in most cases (as opposed to rare exceptional cases) for it to be
silenced, it shouldn't be there in the first place.
--
Stas Malyshev
smalyshev@gmail.com
Hi!
To get the same benefits (jit and such) wouldn't it be better to introduce
a "use function root;" or similar statement or a declare() to specify this
file imports all root functions?We already have this right now, and realistically speaking, who wouldn't
do that in their code instead of writing weird \strlen() code? Everybody
would configure their IDEs and so to insert this automatically. So we're
talking about RFC to make people work harder for what they already have
now and then end up in the same place we are already right now.
I agree with Stas that this "use function root;" or whatever is pointless.
was acted on at any time in the future. and in addition people will silence
the notices on global error reporting level, because violations wouldAnd note also that we can't silence just this warning. Which means
people would have to silence all warnings, thus making all other
messages useless. This is not a good development and this is not what we
should be training users to do - saying "well, it's a warning, just
silence it" is the worth idea we could have. If we create a warning,
recommendation should be "it's important enough so we call your
attention to it, please deal with it", not "just silence it". If it's OK
in most cases (as opposed to rare exceptional cases) for it to be
silenced, it shouldn't be there in the first place.
We have nearly zero E_STRICT
warnings right now. Simply configure your
error reporting level to omit E_STRICT
if you don't want them. You are
blowing this out of proportion.
To get the same benefits (jit and such) wouldn't it be better to introduce
a "use function root;" or similar statement or a declare() to specify this
file imports all root functions?We already have this right now, […]
Do we? AFAIK, it is not possible to import all functions (or even all
symbols, for that matter) of a namespace, without explicitly mentioning
them.
--
Christoph M. Becker
May I propose a compromise?
If I understand what I've read over, the default of functions and constants
to global scope is the primary blocking issue for creating an autoloader
for these elements. Where that not PHP's behavior this functionality could
have been implemented by now.
The problem is that behavior has been around so long that any attempt to
change it would incur a massive amount of changes. Using the E_STRICT
notice level instead of E_DEPRECATED
has been floated as one fix for this,
but this doesn't change the fact that major applications and frameworks,
such as Drupal, pride themselves in being able to pass all tests even with
E_STRICT
enabled. The maintainers of these projects would be annoyed to say
the least to need to fix thousands of lines of code to get back to that
point, and downstream projects such as Drupal could end up waiting years
for all their upstream libraries to get their act together.
Since the two issues are somewhat tied, why not bind them to a
configuration flag following the pattern that was used to ultimately remove
register_globals functionality from the language? At this point let it be
known that when constant/function overloaders hit a php.ini config option
will be added to turn them on -- and turning them on will turn global
scoping for functions off.
This solution isn't perfect. From where Drupal stands, even if all it's
own code stopped using global functions the packages it relies on likely
will continue to do so for some time. Even if they don't, there may be
compatibility issues with the newer version.
A slightly better solution would be to allow this to be set on a per
namespace basis, but as PHP has no true notion of a namespace I don't think
this can be implemented. The declare() statement might allow it to be done
on a per file basis, but that's going to get messy fast.
Still, I feel it is a workable approach despite the drawbacks. If anything
this problem highlights another problem elsewhere in PHP - the inability to
isolate package configuration, or configure packages at all. But that's a
topic for another RFC, one I won't be starting cause I have no idea how to
fix it.
On Mon, Feb 5, 2018 at 8:09 AM, Christoph M. Becker cmbecker69@gmx.de
wrote:
To get the same benefits (jit and such) wouldn't it be better to
introduce
a "use function root;" or similar statement or a declare() to specify
this
file imports all root functions?We already have this right now, […]
Do we? AFAIK, it is not possible to import all functions (or even all
symbols, for that matter) of a namespace, without explicitly mentioning
them.--
Christoph M. Becker
The problem is that behavior has been around so long that any attempt to
change it would incur a massive amount of changes. Using theE_STRICT
notice level instead ofE_DEPRECATED
has been floated as one fix for this,
but this doesn't change the fact that major applications and frameworks,
such as Drupal, pride themselves in being able to pass all tests even with
E_STRICT
enabled. The maintainers of these projects would be annoyed to say
the least to need to fix thousands of lines of code to get back to that
point, and downstream projects such as Drupal could end up waiting years
for all their upstream libraries to get their act together.
Much like any upgrade requiring patches for full compliance with newer PHP
versions, it needs work.
The typical workflow is:
- add PHP.NEXT to the CI setup
- run everything through the tests again, figure out how much has broken
- fix it
In this case, we even already have multiple tools that automatically
fix this problem in one shot.
Since the two issues are somewhat tied, why not bind them to a
configuration flag following the pattern that was used to ultimately remove
register_globals functionality from the language? At this point let it be
known that when constant/function overloaders hit a php.ini config option
will be added to turn them on -- and turning them on will turn global
scoping for functions off.
Argh
Marco Pivetta
The problem is that behavior has been around so long that any attempt to
change it would incur a massive amount of changes. Using theE_STRICT
notice level instead ofE_DEPRECATED
has been floated as one fix for this,
but this doesn't change the fact that major applications and frameworks,
such as Drupal, pride themselves in being able to pass all tests even with
E_STRICT
enabled. The maintainers of these projects would be annoyed to
say
the least to need to fix thousands of lines of code to get back to that
point, and downstream projects such as Drupal could end up waiting years
for all their upstream libraries to get their act together.Much like any upgrade requiring patches for full compliance with newer
PHP versions, it needs work.The typical workflow is:
- add PHP.NEXT to the CI setup
- run everything through the tests again, figure out how much has broken
- fix it
In this case, we even already have multiple tools that automatically
fix this problem in one shot.Since the two issues are somewhat tied, why not bind them to a
configuration flag following the pattern that was used to ultimately
remove
register_globals functionality from the language? At this point let it be
known that when constant/function overloaders hit a php.ini config option
will be added to turn them on -- and turning them on will turn global
scoping for functions off.Argh
Agreed, but you can't just pull the rug out from under people. It's
painful, but it's better to let people opt in to such a major change than
to "break" their code.
Marco Pivetta
On Mon, Feb 5, 2018 at 3:28 PM, Michael Morris tendoaki@gmail.com
wrote:The problem is that behavior has been around so long that any attempt to
change it would incur a massive amount of changes. Using theE_STRICT
notice level instead ofE_DEPRECATED
has been floated as one fix for
this,
but this doesn't change the fact that major applications and frameworks,
such as Drupal, pride themselves in being able to pass all tests even
with
E_STRICT
enabled. The maintainers of these projects would be annoyed to
say
the least to need to fix thousands of lines of code to get back to that
point, and downstream projects such as Drupal could end up waiting years
for all their upstream libraries to get their act together.Much like any upgrade requiring patches for full compliance with newer
PHP versions, it needs work.The typical workflow is:
- add PHP.NEXT to the CI setup
- run everything through the tests again, figure out how much has broken
- fix it
In this case, we even already have multiple tools that automatically
fix this problem in one shot.Since the two issues are somewhat tied, why not bind them to a
configuration flag following the pattern that was used to ultimately
remove
register_globals functionality from the language? At this point let it
be
known that when constant/function overloaders hit a php.ini config option
will be added to turn them on -- and turning them on will turn global
scoping for functions off.Argh
Agreed, but you can't just pull the rug out from under people. It's
painful, but it's better to let people opt in to such a major change than
to "break" their code.
We're talking about a deprecation, not removal of a feature.
First of all, it doesn't remove the feature, which means that everything
keeps working as-is, and second, we already have a way to configure error
reporting for deprecations ("configuration") ;-)
The point of deprecations is precisely to give downstream time to adjust
and release the adapted code, which we do all the time anyway.
Marco Pivetta
Hi!
We're talking about a deprecation, not removal of a feature.
There's no point of deprecating if the goal isn't to remove.
First of all, it doesn't remove the feature, which means that everything
keeps working as-is, and second, we already have a way to configure error
reporting for deprecations ("configuration") ;-)
Configuration removes deprecation messages as a whole class, which is
usually not what you want.
The point of deprecations is precisely to give downstream time to adjust
and release the adapted code, which we do all the time anyway.
In this case, this would mean "edit every file (that uses standard PHP
functions, which is probably nearly every file in the codebase)", to no
benefit to the user. This is a huge imposition on existing users without
any benefit to them. The fact that they will have time is irrelevant -
they always would have all the time in the world but not upgrading - the
point is that this change is bad for them.
Stas Malyshev
smalyshev@gmail.com
Hi!
To get the same benefits (jit and such) wouldn't it be better to introduce
a "use function root;" or similar statement or a declare() to specify this
file imports all root functions?We already have this right now, […]
Do we? AFAIK, it is not possible to import all functions (or even all
symbols, for that matter) of a namespace, without explicitly mentioning
them.
We are talking about global namespace aka standard PHP functions, so it
works out of the box. If you're talking about non-global namespace,
there's no such thing as "all functions of a namespace" at all, and even
if there were, in most cases it's the wrong thing (excepting some rare
cases like you want to override all PHP function for testing, etc.) to
do. Namespaces are meant to keep things separate, so blanket imports
just put us back into a pre-namespace world with all the problems that
existed there.
Granted, there are rare cases - as overriding whole extension or whole
standard library - but they are rare. In overwhelming majority of cases,
this is not what should be done and if you do it, you usually get in
trouble.
Stas Malyshev
smalyshev@gmail.com
Do we? AFAIK, it is not possible to import all functions (or even all
symbols, for that matter) of a namespace, without explicitly mentioning
them.We are talking about global namespace aka standard PHP functions, so it
works out of the box. […]
Ah, I see. :)
--
Christoph M. Becker
If you implement scalar objects:
https://github.com/nikic/scalar_objects
Then 80% of global functions (array_, str_) will be localized using
scalar object methods ($array->split(), $string->join()) and the PHP
developer's response will be positive.
Thanks.
On Sun, Feb 4, 2018 at 10:56 PM, Stanislav Malyshev smalyshev@gmail.com
wrote:
Hi!
To get the same benefits (jit and such) wouldn't it be better to
introduce
a "use function root;" or similar statement or a declare() to specify
this
file imports all root functions?We already have this right now, and realistically speaking, who wouldn't
do that in their code instead of writing weird \strlen() code? Everybody
would configure their IDEs and so to insert this automatically. So we're
talking about RFC to make people work harder for what they already have
now and then end up in the same place we are already right now.
Yes we do have root namespace lookup, but its not automatic, it is only as
a fallback. This RFC is about removing the intermediate namespace'd check,
hence requiring \strlen.
My idea was to force all function lookups into the global nameespace first
by doing the declare or use. This way someone writing a file could state "i
dont use namespaced functions in this file, don't try to load them".
I agree its annoying and more work, just wanted to present it as an
alternative option.
was acted on at any time in the future. and in addition people will
silence
the notices on global error reporting level, because violations wouldAnd note also that we can't silence just this warning. Which means
people would have to silence all warnings, thus making all other
messages useless. This is not a good development and this is not what we
should be training users to do - saying "well, it's a warning, just
silence it" is the worth idea we could have. If we create a warning,
recommendation should be "it's important enough so we call your
attention to it, please deal with it", not "just silence it". If it's OK
in most cases (as opposed to rare exceptional cases) for it to be
silenced, it shouldn't be there in the first place.
Yes, this is why I have a problem with using E_STRICT
(we don't have a lot
of them at the moment, but maybe in preparation of 8 more?) warning for it.
It would send a wrong signal to ignore rather than fix, because the amount
of violations would be massive.
--
Stas Malyshev
smalyshev@gmail.com
On Sun, Feb 4, 2018 at 10:56 PM, Stanislav Malyshev smalyshev@gmail.com
wrote:Hi!
To get the same benefits (jit and such) wouldn't it be better to
introduce
a "use function root;" or similar statement or a declare() to specify
this
file imports all root functions?We already have this right now, and realistically speaking, who wouldn't
do that in their code instead of writing weird \strlen() code? Everybody
would configure their IDEs and so to insert this automatically. So we're
talking about RFC to make people work harder for what they already have
now and then end up in the same place we are already right now.Yes we do have root namespace lookup, but its not automatic, it is only as
a fallback. This RFC is about removing the intermediate namespace'd check,
hence requiring \strlen.My idea was to force all function lookups into the global nameespace first
by doing the declare or use. This way someone writing a file could state "i
dont use namespaced functions in this file, don't try to load them".I agree its annoying and more work, just wanted to present it as an
alternative option.was acted on at any time in the future. and in addition people will
silence
the notices on global error reporting level, because violations wouldAnd note also that we can't silence just this warning. Which means
people would have to silence all warnings, thus making all other
messages useless. This is not a good development and this is not what we
should be training users to do - saying "well, it's a warning, just
silence it" is the worth idea we could have. If we create a warning,
recommendation should be "it's important enough so we call your
attention to it, please deal with it", not "just silence it". If it's OK
in most cases (as opposed to rare exceptional cases) for it to be
silenced, it shouldn't be there in the first place.Yes, this is why I have a problem with using
E_STRICT
(we don't have a lot
of them at the moment, but maybe in preparation of 8 more?) warning for it.
It would send a wrong signal to ignore rather than fix, because the amount
of violations would be massive.
It's fine to ignore them as long as they fix them later. That's
precisely why I think E_STRICT
is a good category for these notices.
If, however, they ignore them forever that's their fault; we are
simply providing advanced notice of a behavior we'd like to eventually
change.
Let me put "eventually" into perspective. We will probably have a 7.3
before we have an 8.0. This means that 8.0, the absolute earliest
version we could remove this feature, is at least 2 years away before
it reaches any of our users. Unless we extend it like we did with
the last 5.X release (and I think we probably should extend it) this
means that users can run their existing code on an officially
supported PHP 7 release for the next 4 years at the minimum. I am
fairly confident that for one reason or another it will delay another
year or two, putting it at 5-6 years.
If we are uncomfortable removing this feature in PHP 8.0 that means
support would extend until the end of the last PHP 8 release. My best
guess is that is at least 5 more years but probably more. That puts us
in the 10-12 years timeframe. If we cannot fix such an issue over an
entire decade then we may as well call PHP 7 the last major release.
And let me be clear: I would like there to be a PHP 8 and a PHP 9. I
think most of our users would like that as well. This means we have
breaking to do over the next decade. The responsible thing is to give
users this information as early as possible.
It's fine to ignore them as long as they fix them later. That's
precisely why I thinkE_STRICT
is a good category for these notices.
If, however, they ignore them forever that's their fault; we are
simply providing advanced notice of a behavior we'd like to eventually
change.Let me put "eventually" into perspective. We will probably have a 7.3
before we have an 8.0. This means that 8.0, the absolute earliest
version we could remove this feature, is at least 2 years away before
it reaches any of our users. Unless we extend it like we did with
the last 5.X release (and I think we probably should extend it) this
means that users can run their existing code on an officially
supported PHP 7 release for the next 4 years at the minimum. I am
fairly confident that for one reason or another it will delay another
year or two, putting it at 5-6 years.
I think for a lot of people the "forever" in your first paragraph and the
"5-6 years" in your second paragraph will feel like the same thing. If the
message is "this might be removed some time in the next decade", people
will simply shrug and ignore it until an actual removal is announced;
thinking as a cynical user, there's no guarantee the recommendation won't
be changed back in future - we've had features "undeprecated" before.
As others have pointed out, even if you run an analyser over your own code
base to add \ in the appropriate places, you can't turn on E_STRICT
notices
without being flooded until all your dependencies have done the same - and
there's no compelling reason for them to do so.
That's why I think having some concrete benefit much sooner is the only way
to stop people resenting this change. Build function autoloading in a way
that it only works if you opt out of the fallback, and then deprecate the
fallback mode, and it feels like progress rather than disruptive tinkering.
Regards,
Rowan Collins
[IMSoP]
It's fine to ignore them as long as they fix them later. That's
precisely why I thinkE_STRICT
is a good category for these notices.
If, however, they ignore them forever that's their fault; we are
simply providing advanced notice of a behavior we'd like to eventually
change.Let me put "eventually" into perspective. We will probably have a 7.3
before we have an 8.0. This means that 8.0, the absolute earliest
version we could remove this feature, is at least 2 years away before
it reaches any of our users. Unless we extend it like we did with
the last 5.X release (and I think we probably should extend it) this
means that users can run their existing code on an officially
supported PHP 7 release for the next 4 years at the minimum. I am
fairly confident that for one reason or another it will delay another
year or two, putting it at 5-6 years.I think for a lot of people the "forever" in your first paragraph and the
"5-6 years" in your second paragraph will feel like the same thing. If the
message is "this might be removed some time in the next decade", people
will simply shrug and ignore it until an actual removal is announced;
thinking as a cynical user, there's no guarantee the recommendation won't
be changed back in future - we've had features "undeprecated" before.As others have pointed out, even if you run an analyser over your own code
base to add \ in the appropriate places, you can't turn onE_STRICT
notices
without being flooded until all your dependencies have done the same - and
there's no compelling reason for them to do so.That's why I think having some concrete benefit much sooner is the only way
to stop people resenting this change. Build function autoloading in a way
that it only works if you opt out of the fallback, and then deprecate the
fallback mode, and it feels like progress rather than disruptive tinkering.
This thinking is too pessimistic. We cannot design to appease our
worst users. The advanced notice is better than a sudden one even if
we have function autoloading.
That's why I think having some concrete benefit much sooner is the only
way
to stop people resenting this change. Build function autoloading in a way
that it only works if you opt out of the fallback, and then deprecate
the
fallback mode, and it feels like progress rather than disruptive
tinkering.This thinking is too pessimistic. We cannot design to appease our
worst users. The advanced notice is better than a sudden one even if
we have function autoloading.
Perhaps I wasn't clear; I'm not saying the transition should be more
sudden, I'm just saying that we should introduce an opt-in advantage
alongside the flood of messages.
As I understand it, the timeline you support is:
- Raise
E_STRICT
in PHP 7.3. - Once we have a plan to actually change the behaviour, move to
E_DEPRECATED, e.g. in PHP 7.5, or 8.0. - Remove fallback at the same time as introducing autoloading, in PHP 8.0
or maybe 9.0.
The timeline I am suggesting is:
- Add an opt-in feature which enables some advantage, probably autoloading,
as soon as possible, e.g. PHP 7.3 or 7.4 - Raise
E_DEPRECATED
for code which doesn't opt in and doesn't
fully-qualify function names, once usage is established, e.g. PHP 7.5, or
8.0 - Remove the fallback mode as a purely internal change, in PHP 8.0 or 9.0.
People would still be changing code on much the same timeline, but we
wouldn't have the long period of telling people to change all their code
without any benefit to them or us.
I also think it's a stretch to call people affected by this change "our
worst users". I don't know if any common coding standards cover leading
backslashes (I searched the PSR-12 draft and Drupal style guide and neither
seems to mention it) but if they do, they're as likely to say "never add
them" as "always add them", particularly given their use as a hack to
"mock" global functions. Or perhaps by "worst users" you mean "users not
willing to change their code" - in which case remember that this is a
disruptive and risky change to an entire code base for no immediate
benefit; putting off such a change might be a perfectly rational decision.
Regards,
Rowan Collins
[IMSoP]
Hi!
I also think it's a stretch to call people affected by this change "our
worst users". I don't know if any common coding standards cover leading
I think you can call them just "our users". I haven't seen any code that
does \strlen or \substr all over the code base. In my opinion, requiring
this would be a huge annoyance to our users and make no sense at all.
--
Stas Malyshev
smalyshev@gmail.com
It's fine to ignore them as long as they fix them later. That's
precisely why I thinkE_STRICT
is a good category for these notices.
If, however, they ignore them forever that's their fault; we are
simply providing advanced notice of a behavior we'd like to eventually
change.Let me put "eventually" into perspective. We will probably have a 7.3
before we have an 8.0. This means that 8.0, the absolute earliest
version we could remove this feature, is at least 2 years away before
it reaches any of our users. Unless we extend it like we did with
the last 5.X release (and I think we probably should extend it) this
means that users can run their existing code on an officially
supported PHP 7 release for the next 4 years at the minimum. I am
fairly confident that for one reason or another it will delay another
year or two, putting it at 5-6 years.I think for a lot of people the "forever" in your first paragraph and the
"5-6 years" in your second paragraph will feel like the same thing. If the
message is "this might be removed some time in the next decade", people
will simply shrug and ignore it until an actual removal is announced;
thinking as a cynical user, there's no guarantee the recommendation won't
be changed back in future - we've had features "undeprecated" before.As others have pointed out, even if you run an analyser over your own code
base to add \ in the appropriate places, you can't turn onE_STRICT
notices
without being flooded until all your dependencies have done the same - and
there's no compelling reason for them to do so.That's why I think having some concrete benefit much sooner is the only way
to stop people resenting this change. Build function autoloading in a way
that it only works if you opt out of the fallback, and then deprecate the
fallback mode, and it feels like progress rather than disruptive tinkering.Regards,
Potential benefits of this change aside, I have to agree with Rowan on tactics.
A carrot works much better than a stick in this case. Remember also that many
larger systems stay around and in production WAAAAAAAAAAAAY past their
expected lifetimes; there are still poor souls running PHP 4, and I personally
know of Drupal 5 sites still in the wild. So even if the HEAD version of
everything is updated within a year for such a change the long tail of what's
running out in the world will lag badly.
That said, I'm not sure that function autoloading will be that big of a carrot
for the major projects at this point. Wordpress is going to ignore anything
we do here anyway for at least 15 years, and pretty much every other project
in existence has gone all-OOP or nearly-all-OOP at this point (good or bad is
beside the point). Namespaced user defined functions are rare in my experience
outside of very specific libraries (such as functional tooling libs). So "yay,
you can now autoload namespaced user-defined functions" will likely be met with
a lot of "what are those?"
--Larry Garfield
On Tue, Feb 6, 2018 at 8:24 AM, Larry Garfield larry@garfieldtech.com
wrote:
That said, I'm not sure that function autoloading will be that big of a
carrot
for the major projects at this point. Wordpress is going to ignore
anything
we do here anyway for at least 15 years, and pretty much every other
project
in existence has gone all-OOP or nearly-all-OOP at this point (good or bad
is
beside the point). Namespaced user defined functions are rare in my
experience
outside of very specific libraries (such as functional tooling libs). So
"yay,
you can now autoload namespaced user-defined functions" will likely be met
with
a lot of "what are those?"
I disagree with this assessment. Many functions are actually collected in
static classes so they can be autoloaded. So instead of,
namespace Foo\Bar;
class Map {
public static function modelToApi(Model $model) : array {}
}
The function can now just be in a namespace directly, instead of treating a
class like a namespace. You can then also import just the function you
need, instead of the whole class. Many of these classes exist in projects
I've worked on just for the purpose of being able to autoload the functions
when needed. My 2 cents.
--Larry Garfield
Hi!
That said, I'm not sure that function autoloading will be that big of a carrot
for the major projects at this point. Wordpress is going to ignore anything
If they pay for that is to edit every single file that uses global
functions (which is all of them) or suffer a hailstorm of warnings then
I don't think any carrot would be large enough for this. And, frankly,
the amount of cases where I absolutely needed namespace function
autoloading and couldn't do without it (like, using classes) I probably
could count on the fingers of one hand, and I still could type while
doing it.
I mean, I don't necessarily have anything against adding this feature,
but if the progression goes from "we need namespaced functions" to "we
need namespaced autoloaded functions" to "we can't use strlen without
ridiculous prefixing or adding "yes, I still want strlen" in every file
every time" then I'd rather not have namespaced functions at all than
deal with that.
outside of very specific libraries (such as functional tooling libs). So "yay,
you can now autoload namespaced user-defined functions" will likely be met with
a lot of "what are those?"
It won't be just "yay, you can now autoload namespaced user-defined
functions", it would be "yay, all code that uses strlen is not throwing
noisy warnings, but on the other hand, we made this obscure feature you
never used easier, so rejoice!" I wouldn't rejoice.
Stas Malyshev
smalyshev@gmail.com
Hi!
Yes we do have root namespace lookup, but its not automatic, it is only
as a fallback. This RFC is about removing the intermediate namespace'd
check, hence requiring \strlen.
It is automatic, in the meaning you don't have to do anything to get it.
Realistically, how often do you override strlen? If I say "never", I
probably would be close enough for all practical purposes.
My idea was to force all function lookups into the global nameespace
first by doing the declare or use. This way someone writing a file could
state "i dont use namespaced functions in this file, don't try to load
them".
Why? We already have this working, why make it harder by requiring to do
specific things that we know upfront 99%+ people end up doing? Why not
assume them by default?
--
Stas Malyshev
smalyshev@gmail.com
Hi,
Realistically, how often do you override strlen? If I say "never", I
probably would be close enough for all practical purposes.
It's an ironic coincidence that you use strlen()
as an example.
Because it and substr()
are possibly the most likely to be overriden,
where we need code to be byte-safe in spite of mbstring.func_overload.
But why does that matter, either way?
Cheers,
Andrey.
Hi!
It's an ironic coincidence that you use
strlen()
as an example.
Because it andsubstr()
are possibly the most likely to be overriden,
where we need code to be byte-safe in spite of mbstring.func_overload.
Also happens rather rarely, in my impression, since you'd have to a) run
mbstring.func_overload which you can't remove and b) still need
non-overloaded string functions. And if you are in this rare situation,
it's usually better to have explicitly-named function, so that you know
what you are dealing with, not relying on subtle details of how names
are resolved vs. namespaces.
Stas Malyshev
smalyshev@gmail.com
Hello :-),
Thank you for the RFC. I really appreciate it, for sure, but I would
like to raise a concern regarding the atoum test framework [1].
atoum provides 3 mock engines, resp. for class-like entitites,
functions, and constants.
The function and constant mock engines are both based on the same
principle, i.e. it relies on the “entity bubble look up resolution”
algorithm to mock functions or constants. Typically, one might mock the
file_exists
function like this: $this->function->file_exists = function (…) { … };
. In this case, atoum creates a new file_exists
function in the same namespace than the system under test (if testing
A\B\C
, then atoum creates A\B\file_exists
).
It is a very convinient and beloved way to mock functions and constants.
And thus, this RFC raises the following issue: This feature is used a
lot by atoum users. The RFC will destroy this feature. It's not about
atoum loosing a master feature, it's more about: How users will be able
to mock functions and constants after that? This is an important question.
That's a hard question to answer, I know, but in its actual form, the
RFC breaks a non-negligeable part of the testing ecosystem. This is
something to take into account :-).
It is still possible to use moles instead of mocks to achieve the same
behavior, but restricted to user-defined functions only. Moles do not
allow to change the behavior of “VM-defined” functions.
Regards.
Hello PHPeople. I just published the RFC "Deprecation of fallback to root
scope".It is quite a substantial change, but as you can read in the RFC, can be a
(basically) transparent one.
I'm referring to the possibility to shim it in userland. Essentially, this
would move the feature from core to userland.I hope you like it. Let me know what you think.
Hey Ivan,
Hello :-),
Thank you for the RFC. I really appreciate it, for sure, but I would like
to raise a concern regarding the atoum test framework [1].
atoum provides 3 mock engines, resp. for class-like entitites, functions,
and constants.
The function and constant mock engines are both based on the same
principle, i.e. it relies on the “entity bubble look up resolution”
algorithm to mock functions or constants. Typically, one might mock the
file_exists
function like this: $this->function->file_exists = function (…) { … };
. In this case, atoum creates a new file_exists
function in
the same namespace than the system under test (if testing A\B\C
, then
atoum creates A\B\file_exists
).
It is a very convinient and beloved way to mock functions and constants.
And thus, this RFC raises the following issue: This feature is used a lot
by atoum users. The RFC will destroy this feature. It's not about atoum
loosing a master feature, it's more about: How users will be able to mock
functions and constants after that? This is an important question.
That's a hard question to answer, I know, but in its actual form, the RFC
breaks a non-negligeable part of the testing ecosystem. This is something
to take into account :-).
It is still possible to use moles instead of mocks to achieve the same
behavior, but restricted to user-defined functions only. Moles do not allow
to change the behavior of “VM-defined” functions.
Regards.
See https://externals.io/message/101745#101752
The problem is always with routines (not functions)) that rely on shared
global mutable state.
Mocking those is generally a problem, as it exposes a dependency inversion
issue, rather than actually getting rid of an implicit reliance on global
state that is not declared to consumers of a SUT.
See https://externals.io/message/101745#101752
The problem is always with routines (not functions)) that rely on shared
global mutable state.Mocking those is generally a problem, as it exposes a dependency inversion
issue, rather than actually getting rid of an implicit reliance on global
state that is not declared to consumers of a SUT.
While that would be a perfectly fine justification for not adding this
feature, it doesn't address the impact of removing the feature now that it
has existed for over 8 years. Even before the feature is actually removed,
anyone using such tests would be faced with the following options:
- Put up with hundreds of notices until they have a chance to completely
refactor the code in question. - Suppress all messages of a particular level (possibly
E_STRICT
initially
andE_DEPRECATED
later) until they have the chance to refactor. - Prepend \ to global function references, purely to stop the deprecation
notices, and break all tests that relied on this mocking mechanism.
None of these options is particularly appealing, and this will all be for a
hypothetical future improvement to the language.
Regards,
Rowan Collins
[IMSoP]
On Mon, Feb 5, 2018 at 1:52 PM, Rowan Collins rowan.collins@gmail.com
wrote:
None of these options is particularly appealing, and this will all be for a
hypothetical future improvement to the language.
Would proposing a function autoloading RFC together with this improve the
situation?
Marco Pivetta
On Mon, Feb 5, 2018 at 1:52 PM, Rowan Collins rowan.collins@gmail.com
wrote:None of these options is particularly appealing, and this will all be for
a
hypothetical future improvement to the language.Would proposing a function autoloading RFC together with this improve the
situation?
I think it would, firstly because it gives a visible benefit to the change
we would be asking users to make, and secondly because it allows a shim
like the example in the RFC to be used immediately as a transition.
As I mentioned in an aside previously, it would also make an opt-in
statement more reasonable, because saying "namespace Foo\Bar with autoload"
could both turn off the fallback lookup and turn on autoloading functions
in the current namespace. Fully-qualified function names could be
autoloaded in both modes, and presumably functions explicitly imported with
"use" could be too.
Regards,
Rowan Collins
[IMSoP]
Hi!
None of these options is particularly appealing, and this will all be for a
hypothetical future improvement to the language.Would proposing a function autoloading RFC together with this improve the
situation?
No. Function autoloading addresses the needs of tiny part of the users.
While I am far from discounting these needs - they are still valid needs
and we may want to serve them if we can - if the costs is to impose a
huge burden on the rest of the users it doesn't make it much better.
It's the situation of "we just broke all your code" vs. "we just broke
all your code, but some of our code is now easier to write". Not much
of an improvement, I think.
--
Stas Malyshev
smalyshev@gmail.com
Hello PHPeople. I just published the RFC "Deprecation of fallback to
root
scope".
Given the discussion so far, how about taking the "opposite" approach:
deprecate unprefixed reference to functions which are in the current
namespace.
Proposal:
- PHP 7.3: Add syntax to explicitly reference functions and constants in
the current namespace, such as .\foo or this\foo - PHP 7.4: Raise
E_DEPRECATED
whenever an unprefixed function/constant
resolves to something in the current namespace (other than via "use" alias) - PHP 8.0: Make all unprefixed functions/constants always refer to the root
namespace
Pros:
- Much less disruptive change, as the majority of unprefixed function calls
are to global functions, and would not need to change. - Both cases can be made unambiguous if the author wants to.
- Apparently OpCache currently mitigates the performance hit by caching
lookups in a technically unclean way. Users hit by this can make their code
unambiguous in 7.3, and the optimisation will become clean in 8.0. - Function / constant autoloading can be added in 7.x if we accept the
caveat that unprefixed functions will not be autoloaded; or in 8.0 if we
want to cover everything.
Cons:
- Slightly uglier syntax.
- Still a breaking change (in 8.0).
- Class names will still be resolved differently from function and constant
names. - Code actively using the fallback system (e.g. tests masking global
functions with mocks) will need refactoring as there is no way to opt into
the old behaviour. - The .\foo() syntax may appear in similar places to the . concatenation
operator. Even if technically unambiguous and implementable in the parser,
this may be confusing to users. A keyword approach like this\foo() would be
clearer, but more verbose.
What do people think? Is it worth expanding this out into an alternative
RFC?
Regards,
Rowan Collins [IMSoP]
- PHP 7.3: Add syntax to explicitly reference functions and constants in
the current namespace, such as .\foo or this\foo
It is already possible to use the namespace
keyword for this, see
https://3v4l.org/bikjE.
- Slightly uglier syntax.
IMHO, .\foo is very ugly, and namespace\foo is not much better.
--
Christoph M. Becker
- PHP 7.3: Add syntax to explicitly reference functions and constants in
the current namespace, such as .\foo or this\fooIt is already possible to use the
namespace
keyword for this, see
https://3v4l.org/bikjE.
Huh, I never knew that! Funnily enough, I thought of that as a possibility
(because it's already a reserved word) but rejected it as too long. :P
- Slightly uglier syntax.
IMHO, .\foo is very ugly, and namespace\foo is not much better.
Yeah; the question is whether that ugliness is something we're willing to
live with for the performance and features it would enable. Most code would
still be less ugly than if we had to prefix all global functions, anyway.
Something worth considering is that even when using namespaced functions,
the shorthand is only available in exactly the current namespace, so
you're rather likely to be qualifying or importing them anyway. For
instance, they might be in a child or neighbouring namespace called
"...\functions" or " ...\ utils" or " ...\ streams".
Regards,
Rowan Collins
[IMSoP]
Hello PHPeople. I just published the RFC "Deprecation of fallback to
root
scope".Given the discussion so far, how about taking the "opposite" approach:
deprecate unprefixed reference to functions which are in the current
namespace.Proposal:
- PHP 7.3: Add syntax to explicitly reference functions and constants in
the current namespace, such as .\foo or this\foo- PHP 7.4: Raise
E_DEPRECATED
whenever an unprefixed function/constant
resolves to something in the current namespace (other than via "use" alias)- PHP 8.0: Make all unprefixed functions/constants always refer to the root
namespacePros:
- Much less disruptive change, as the majority of unprefixed function calls
are to global functions, and would not need to change.- Both cases can be made unambiguous if the author wants to.
- Apparently OpCache currently mitigates the performance hit by caching
lookups in a technically unclean way. Users hit by this can make their code
unambiguous in 7.3, and the optimisation will become clean in 8.0.- Function / constant autoloading can be added in 7.x if we accept the
caveat that unprefixed functions will not be autoloaded; or in 8.0 if we
want to cover everything.Cons:
- Slightly uglier syntax.
- Still a breaking change (in 8.0).
- Class names will still be resolved differently from function and constant
names.- Code actively using the fallback system (e.g. tests masking global
functions with mocks) will need refactoring as there is no way to opt into
the old behaviour.- The .\foo() syntax may appear in similar places to the . concatenation
operator. Even if technically unambiguous and implementable in the parser,
this may be confusing to users. A keyword approach like this\foo() would be
clearer, but more verbose.What do people think? Is it worth expanding this out into an alternative
RFC?Regards,
Rowan Collins [IMSoP]
My opinion is that the result is both uglier and even less
consistent with namespaced types. I'm glad you are at least thinking
about alternative proposals but this is worse than both the original
proposal and doing nothing.
Hi,
What's not obvious (to me at least) here is why is the current
behavior preventing a ("sensible", as the RFC desribes it)
implementation of function autoloading? That seems to be a major
motivation factor for the proposal, yet doesn't seem to be explained
anywhere.
Cheers,
Andrey.
Hi,
What's not obvious (to me at least) here is why is the current
behavior preventing a ("sensible", as the RFC desribes it)
implementation of function autoloading? That seems to be a major
motivation factor for the proposal, yet doesn't seem to be explained
anywhere.
It's not been mentioned explicitly in this thread, but has come up a lot in
previous discussions. I'll attempt to summarise my understanding.
Currently, when you write "foo()" in code marked as namespace "Bob", the
engine does this:
- Check for a function "Bob\foo", use it if defined
- Check for a function "foo", use it if defined
- Raise an error if neither is defined
If we add autoloading of functions, the logical sequence would be to
attempt the autoloader every time we encounter something not defined:
- Check for a function "Bob\foo", use it if defined
1a. Run autoloader callback for "Bob\foo"; use function if one is now
defined - Check for a function "foo", use it if defined
2a. Run autoloader callback for "foo"; use function if one is now defined - Raise an error if neither is defined
The problem is that all of this has to happen every time you call the
function, because at any time, the function could be registered, or a new
autoloader registered that knows where to find it.
If "foo" is actually a global function, that means steps 1 and 1a will be
run every time your use of "foo()" is reached, meaning that every call has
an additional overhead of calling the autoloader callback.
Since the autoloader callback might in fact be a whole stack of registered
closures, this means a significant overhead every time you mention any
global function, which includes 90% of PHP's standard library.
I hope that clarifies the general problem (and that I haven't made any
mistakes in my explanation).
Regards,
Rowan Collins
[IMSoP]