Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.
I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...
https://wiki.php.net/rfc/engine_warnings
Regards,
Nikita
Hi Nikita,
This RFC makes me very happy! I have a few points that I didn't find
clarification on in the RFC. For "Undefined variable: %s" the new proposal
is an Error Exception. For a starter: will it include dynamically declared
variables such as $$foo?
For my second point: in regards of backwards compatibility, is it possible
to first trigger a deprecation for each of the cases that will abort the
flow? If not, I fear I won't be able to upgrade as we still maintain a lot
of legacy code that deals with dynamically declared and undefined
variables, and possibly other violations that we don't know of. We are
working on rewriting all this code but don't have enough developers to
rewrite everything under a few years. If we can start logging these
deprecations, we know where to fix what, rather than having our entire
application crash. This way we can prioritize our maintenance on fixes each
of these cases.
The scenarios where this occurs often in our code base are dynamically
included files that may or may not set a variable. The code is most likely
"broken", but the behavior it produces is what's considered correct at this
point. It can be solved by defining the variable with null value, but it's
hard to trace without logging as we can't always set it with null value.
Regards,
Lynn van der Berg
Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...https://wiki.php.net/rfc/engine_warnings
Regards,
Nikita
Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...
Specifically on undefined variables, the way we deal with them has little
to do with register_globals. It's behavior you can find in other dynamic
languages (e.g. Perl), and allows for certain code patterns (which rely on
the automatic creation of a variable whenever it's used in write context,
and on a default known-in-advance value in case it's used in a read
context). It's fine not to like this behavior or the code patterns that
commonly rely on it (e.g., @$foo++), but it's intentional and isn't related
to any historical reasons.
I think many (if not all) of your proposals make sense, but most of them
make sense as an opt-in - perhaps using something similar to Perl's strict
mode (which incidentally, changes the way the language treats undefined
variables in exactly the same way). This would also provide a future-proof
solution for additional similarly-themed proposals (such as strict ops,
etc.).
Zeev
On Wed, Aug 28, 2019 at 12:33 PM Nikita Popov nikita.ppv@gmail.com
wrote:Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...Specifically on undefined variables, the way we deal with them has little
to do with register_globals. It's behavior you can find in other dynamic
languages (e.g. Perl), and allows for certain code patterns (which rely on
the automatic creation of a variable whenever it's used in write context,
and on a default known-in-advance value in case it's used in a read
context). It's fine not to like this behavior or the code patterns that
commonly rely on it (e.g., @$foo++), but it's intentional and isn't related
to any historical reasons.
This argument makes sense for arrays and objects (and I don't promote
undefined index/property to exceptions for that reason), but I don't think
it holds any water for simple variables. Writing @$counts[$key]++ is a lazy
way to count values and avoid ugly boilerplate for if
(isset($counts[$key])) { $counts[$key]++; } else { $counts[$key] = 1; }.
But @$foo++ is just a really bad way of writing either $foo++ or $foo = 1.
Outside of variable variables, the concept of a conditionally defined
variable just doesn't make a lot of sense.
I think many (if not all) of your proposals make sense, but most of them
make sense as an opt-in - perhaps using something similar to Perl's strict
mode (which incidentally, changes the way the language treats undefined
variables in exactly the same way). This would also provide a future-proof
solution for additional similarly-themed proposals (such as strict ops,
etc.).
I don't think this is an appropriate use of an opt-in. It's a case where we
can balance language cleanup with backwards compatibility concerns. Code
that works after this proposal will also work before it, and as such there
is no danger of ecosystem bifurcation that would need to be addressed by an
opt-in.
Thanks,
Nikita
This argument makes sense for arrays and objects (and I don't promote
undefined index/property to exceptions for that reason), but I don't think
it holds any water for simple variables. Writing @$counts[$key]++ is a lazy
way to count values and avoid ugly boilerplate for if
(isset($counts[$key])) { $counts[$key]++; } else { $counts[$key] = 1; }.
But @$foo++ is just a really bad way of writing either $foo++ or $foo = 1.
Outside of variable variables, the concept of a conditionally defined
variable just doesn't make a lot of sense.
The variables are not conditionally declared on purpose, but as it's code
written 15~20 years ago, maintained, copy-pasted over and over and never
reviewed, there's a lot of issues that remain that my trigger an error
exception if this proposal is passed without migration path.
// a.php
if ($someCondition) { // comes from another file, never used, can't verify
existance
$foo = 'foo';
}
// b.php
$bar = 'bar';
// scenario1.php
include 'a.php'; // this would crash
include 'b.php';
echo $foo . $bar; // this would crash if the include didn't yet
// scenario2.php
$someCondition = true;
include 'a.php'; // this would not crash
include 'b.php';
echo $foo . $bar; // this would not crash
The problem with the above legacy code, which we sadly have spread through
a spaghetti of thousands of files, is that if it starts throwing errors
with no migration path, we simply can't update without spending possibly
weeks debugging and trying to find scenarios where this might trigger. Now
I'm not sure, but if I would've used include_once
and combine this with
function/class scopes (people loved to do that in our legacy code), all
hell breaks loose and it will be nearly impossible to find the cases.
All I'm asking is for a clear upgrade path with deprecations so that my
code can be safely migrated over time, rather than have it crash with the
next version. Compared to <?php vs <?, this will break a lot and is not as
easy to fix. By having it throw deprecations which we can easily log to a
specific file, we can gather and fix the cases when we have time to spend
on technical debt, and by the time the warning will turn into an error
exception, we'll have fixed probably 90%+ of the cases, making the upgrade
possible.
Regards,
Lynn van der Berg
This argument makes sense for arrays and objects (and I don't promote
undefined index/property to exceptions for that reason), but I don't think
it holds any water for simple variables. Writing @$counts[$key]++ is a
lazy
way to count values and avoid ugly boilerplate for if
(isset($counts[$key])) { $counts[$key]++; } else { $counts[$key] = 1; }.
But @$foo++ is just a really bad way of writing either $foo++ or $foo = 1.
Outside of variable variables, the concept of a conditionally defined
variable just doesn't make a lot of sense.The variables are not conditionally declared on purpose, but as it's code
written 15~20 years ago, maintained, copy-pasted over and over and never
reviewed, there's a lot of issues that remain that my trigger an error
exception if this proposal is passed without migration path.
To be clear, this was in response to Zeev's particular argument, which I
don't think is valid. I am aware that accesses to undefined variables are a
thing in legacy code.
However, I feel pretty strongly that converting any of these to
deprecations is not a good idea. While there's certainly different views on
this, I've seen it often enough deprecation warning are considered an even
lower error level than notices (imagine my surprise when PEAR stopped
working completely in PHP 8 because nobody ever saw the hundreds of
suppressed deprecations). We could throw a deprecation in addition, but I
think this will make the development experience really suck for anyone who
is not actively working on a migration right now (imagine seeing lots of
warnings/notices during development twice).
I think it would be better to register an error handler that matches the
cases that will throw and can then log those. I'd be happy to provide an
implementation if you think this would be useful for your use-case. Also
has the nice advantage that you can start using it right now and don't have
to wait until you upgrade to a release that has deprecations.
Nikita
// a.php if ($someCondition) { // comes from another file, never used, can't verify existance $foo = 'foo'; } // b.php $bar = 'bar'; // scenario1.php include 'a.php'; // this would crash include 'b.php'; echo $foo . $bar; // this would crash if the include didn't yet // scenario2.php $someCondition = true; include 'a.php'; // this would not crash include 'b.php'; echo $foo . $bar; // this would not crash
The problem with the above legacy code, which we sadly have spread through
a spaghetti of thousands of files, is that if it starts throwing errors
with no migration path, we simply can't update without spending possibly
weeks debugging and trying to find scenarios where this might trigger. Now
I'm not sure, but if I would've usedinclude_once
and combine this with
function/class scopes (people loved to do that in our legacy code), all
hell breaks loose and it will be nearly impossible to find the cases.All I'm asking is for a clear upgrade path with deprecations so that my
code can be safely migrated over time, rather than have it crash with the
next version. Compared to <?php vs <?, this will break a lot and is not as
easy to fix. By having it throw deprecations which we can easily log to a
specific file, we can gather and fix the cases when we have time to spend
on technical debt, and by the time the warning will turn into an error
exception, we'll have fixed probably 90%+ of the cases, making the upgrade
possible.Regards,
Lynn van der Berg
However, I feel pretty strongly that converting any of these to
deprecations is not a good idea. While there's certainly different views on
this, I've seen it often enough deprecation warning are considered an even
lower error level than notices (imagine my surprise when PEAR stopped
working completely in PHP 8 because nobody ever saw the hundreds of
suppressed deprecations). We could throw a deprecation in addition, but I
think this will make the development experience really suck for anyone who
is not actively working on a migration right now (imagine seeing lots of
warnings/notices during development twice).
Again, I considered this carefully for undefined constants and discussed it
extensively on the RFC and resulting thread. In short, "deprecation notice"
doesn't have to mean "E_DEPRECATED". Arguably, "severity" and "type" should
be two different dimensions, and E_DEPRECATION_WARNING would be
E_DEPRECATION & E_WARNING; but in practice, a Warning containing the text
"this is deprecated" achieves the goal just fine.
Whatever the mechanism, the point is to make people aware as far in advance
as possible, so that they can start addressing the problem before it
becomes a blocker to upgrading. As briefly mentioned, third-party libraries
are a key case here: if a library raises extra Warnings, I can take the
time to submit a patch to that library, wait for the maintainer to accept
it, and make sure I can use the latest version; if the library raises extra
Errors, I have to delay my upgrade, or run a patched version of the
library, until it's fixed.
Regards,
Rowan Tommins
[IMSoP]
However, I feel pretty strongly that converting any of these to
deprecations is not a good idea. While there's certainly different views on
this, I've seen it often enough deprecation warning are considered an even
lower error level than notices (imagine my surprise when PEAR stopped
working completely in PHP 8 because nobody ever saw the hundreds of
suppressed deprecations). We could throw a deprecation in addition, but I
think this will make the development experience really suck for anyone who
is not actively working on a migration right now (imagine seeing lots of
warnings/notices during development twice).
You got a very valid point here. As long as there is a clear migration
path, albeit with user-land tools, I'll take it.
I think it would be better to register an error handler that matches the
cases that will throw and can then log those. I'd be happy to provide an
implementation if you think this would be useful for your use-case. Also
has the nice advantage that you can start using it right now and don't have
to wait until you upgrade to a release that has deprecations.
It would be great to have a package that reports all these cases, though we
could try to craft something ourselves if this RFC is approved. Perhaps
frameworks providing error handlers can add specific logging for these
scenarios as well, saves you from putting more effort in this than required.
Regards,
Lynn van der Berg
Am 28.08.2019 um 13:10 schrieb Nikita Popov nikita.ppv@gmail.com:
Specifically on undefined variables, the way we deal with them has little
to do with register_globals. It's behavior you can find in other dynamic
languages (e.g. Perl), and allows for certain code patterns (which rely on
the automatic creation of a variable whenever it's used in write context,
and on a default known-in-advance value in case it's used in a read
context). It's fine not to like this behavior or the code patterns that
commonly rely on it (e.g., @$foo++), but it's intentional and isn't related
to any historical reasons.This argument makes sense for arrays and objects (and I don't promote
undefined index/property to exceptions for that reason), but I don't think
it holds any water for simple variables. Writing @$counts[$key]++ is a lazy
way to count values and avoid ugly boilerplate for if
(isset($counts[$key])) { $counts[$key]++; } else { $counts[$key] = 1; }.
But @$foo++ is just a really bad way of writing either $foo++ or $foo = 1.
Outside of variable variables, the concept of a conditionally defined
variable just doesn't make a lot of sense.
We often use the pattern $a .= "xy" or $a[] = "xy" and requiring to initialise leads to either boiler-plate code in often very simple functions or even worse to write the first one as $a = "xy" and $a = ["xy"] which both hurt symmetry and extensibility (you need to change two places if you want to add a new first entry). We are already suppressing the E_NOTICE
for this as the pattern is too useful to fill our logs.
Your simple typo in variable names can be caught well enough by a static analyser, we have a simplistic one in out git commit hook which more than does the job for us. And it does it even better in your average case as it also catches typos in rare code paths not executed by your tests. And no, don't say "make sure you have 100% code coverage", that is a myth.
Summary: Promote E_NOTICE
to E_WARNINGS, fine, make them abort code execution: Don't do it, don't break our code.
For people promoting a stricter PHP mode: Just fix your code if it caused an E_NOTICE/E_WARNING, you don't need an Exception for that. And I don't buy the whole security argument, code has to be secure on a whole different level than undefined variables.
- Chris
On Wed, Aug 28, 2019 at 12:33 PM Nikita Popov nikita.ppv@gmail.com
wrote:Hi internals,
I think it's time to take a look at our existing warnings & notices in
the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...Specifically on undefined variables, the way we deal with them has little
to do with register_globals. It's behavior you can find in other
dynamic languages (e.g. Perl), and allows for certain code patterns (which
rely on the automatic creation of a variable whenever it's used in write
context, and on a default known-in-advance value in case it's used in a
read context). It's fine not to like this behavior or the code patterns
that commonly rely on it (e.g., @$foo++), but it's intentional and isn't
related to any historical reasons.This argument makes sense for arrays and objects (and I don't promote
undefined index/property to exceptions for that reason), but I don't think
it holds any water for simple variables. Writing @$counts[$key]++ is a lazy
way to count values and avoid ugly boilerplate for if
(isset($counts[$key])) { $counts[$key]++; } else { $counts[$key] = 1; }.
But @$foo++ is just a really bad way of writing either $foo++ or $foo = 1.
Outside of variable variables, the concept of a conditionally defined
variable just doesn't make a lot of sense.
This example has nothing to do with arrays. There are many code patterns
in which relying on this behavior makes perfect sense for folks who are a
lot less strictly-minded. For example:
foreach (whatever) {
if (sth) {
@$whCount++;
}
}
Yes, it may be painful for many eyes that $whCount is not explicitly
initialized, but the above code is perfectly legitimate, warning-free
notice-compliant code since forever. Moreover - this isn't legacy - there
are a lot of folks who appreciate this precise behavior, which is
documented and works as expected for the last 20+ years.
Or:
if ($bookCount>0) {
$suffix = 's';
}
print "$bookCount book$suffix";
These are just two simple cases I bumped into myself recently. There's an
infinite supply of more of those where these came from.
I think many (if not all) of your proposals make sense, but most of them
make sense as an opt-in - perhaps using something similar to Perl's strict
mode (which incidentally, changes the way the language treats undefined
variables in exactly the same way). This would also provide a future-proof
solution for additional similarly-themed proposals (such as strict ops,
etc.).I don't think this is an appropriate use of an opt-in. It's a case where
we can balance language cleanup with backwards compatibility concerns. Code
that works after this proposal will also work before it, and as such there
is no danger of ecosystem bifurcation that would need to be addressed by an
opt-in.
Calling this 'cleanup' is opinionated, and avoiding bifurcation by forcing
that opinion on everyone isn't a very good solution for those who have
other opinions. While the opinion that variables must not be used before
being initialized is obviously a valid one - it is just that, one valid
opinion - and there are others. PHP never took this opinion as an
axiomatic requirement (and not because of register_globals) - instead, the
intent was to have a default value for uninitialized variables - a
consistent, documented behavior since the dawn of the language. Can this
be problematic under certain situations? Absolutely. Can it be useful in
other cases? Sure (which is why it's very common). A great deal of folks
both rely on this behavior and *like *it. Those who don't (and there's
plenty of those as well of course) - always had a reasonable solution of
enabling E_STRICT
and enforcing E_STRICT-compliant code. I still think
that having a strict mode (which can encompass strict types, strict ops,
stricter error behavior, etc.) makes a lot of sense and would arguably be a
superior option for the many folks who prefer a stricter language - but
there's simply no way we can change one of the most fundamental behaviors
of the language and force it down people's throats - not only because it
breaks compatibility, but because it breaks how many people are used to
write their PHP code. Perl provided stricter-liking folks with a solution
in the form of 'use strict;' decades ago; JS did something similar much
more recently. Neither of these created any sort of bifurcation - it's a
simple, sensible solution that has virtually no downsides.
Zeev
On Wed, Aug 28, 2019 at 12:33 PM Nikita Popov nikita.ppv@gmail.com
wrote:Hi internals,
I think it's time to take a look at our existing warnings & notices in
the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only
generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though
there's
room for bikeshedding here...Specifically on undefined variables, the way we deal with them has
little
to do with register_globals. It's behavior you can find in other
dynamic languages (e.g. Perl), and allows for certain code patterns
(which
rely on the automatic creation of a variable whenever it's used in write
context, and on a default known-in-advance value in case it's used in a
read context). It's fine not to like this behavior or the code patterns
that commonly rely on it (e.g., @$foo++), but it's intentional and isn't
related to any historical reasons.This argument makes sense for arrays and objects (and I don't promote
undefined index/property to exceptions for that reason), but I don't
think
it holds any water for simple variables. Writing @$counts[$key]++ is a
lazy
way to count values and avoid ugly boilerplate for if
(isset($counts[$key])) { $counts[$key]++; } else { $counts[$key] = 1; }.
But @$foo++ is just a really bad way of writing either $foo++ or $foo =
Outside of variable variables, the concept of a conditionally defined
variable just doesn't make a lot of sense.This example has nothing to do with arrays. There are many code patterns
in which relying on this behavior makes perfect sense for folks who are a
lot less strictly-minded. For example:foreach (whatever) {
if (sth) {
@$whCount++;
}
}Yes, it may be painful for many eyes that $whCount is not explicitly
initialized, but the above code is perfectly legitimate, warning-free
notice-compliant code since forever. Moreover - this isn't legacy - there
are a lot of folks who appreciate this precise behavior, which is
documented and works as expected for the last 20+ years.Or:
if ($bookCount>0) {
$suffix = 's';
}print "$bookCount book$suffix";
These are just two simple cases I bumped into myself recently. There's an
infinite supply of more of those where these came from.I think many (if not all) of your proposals make sense, but most of them
make sense as an opt-in - perhaps using something similar to Perl's
strict
mode (which incidentally, changes the way the language treats undefined
variables in exactly the same way). This would also provide a
future-proof
solution for additional similarly-themed proposals (such as strict ops,
etc.).I don't think this is an appropriate use of an opt-in. It's a case where
we can balance language cleanup with backwards compatibility concerns.
Code
that works after this proposal will also work before it, and as such
there
is no danger of ecosystem bifurcation that would need to be addressed by
an
opt-in.Calling this 'cleanup' is opinionated, and avoiding bifurcation by forcing
that opinion on everyone isn't a very good solution for those who have
other opinions. While the opinion that variables must not be used before
being initialized is obviously a valid one - it is just that, one valid
opinion - and there are others. PHP never took this opinion as an
axiomatic requirement (and not because of register_globals) - instead, the
intent was to have a default value for uninitialized variables - a
consistent, documented behavior since the dawn of the language. Can this
be problematic under certain situations? Absolutely. Can it be useful in
other cases? Sure (which is why it's very common). A great deal of folks
both rely on this behavior and *like *it. Those who don't (and there's
plenty of those as well of course) - always had a reasonable solution of
enablingE_STRICT
and enforcing E_STRICT-compliant code. I still think
that having a strict mode (which can encompass strict types, strict ops,
stricter error behavior, etc.) makes a lot of sense and would arguably be a
superior option for the many folks who prefer a stricter language - but
there's simply no way we can change one of the most fundamental behaviors
of the language and force it down people's throats - not only because it
breaks compatibility, but because it breaks how many people are used to
write their PHP code. Perl provided stricter-liking folks with a solution
in the form of 'use strict;' decades ago; JS did something similar much
more recently. Neither of these created any sort of bifurcation - it's a
simple, sensible solution that has virtually no downsides.While I like Zeev's idea of making it opt-in, I think that a deprecation
path is needed at the very least. I think this has the potential to be an
even bigger issue to deal with than short tags. At least short tags have
been discouraged for a long time. The first short tags RFC would have
probably lead to a delay in upgrading to 8.0. This RFC would pretty much
guarantee never being able to upgrade to 8.0 until we've totally retired
our legacy code base... which will probably be just in time for PHP 28.0 -
assuming the PHP project isn't dead at that point due to this RFC.
Zeev
--
Chase Peeler
chasepeeler@gmail.com
On Wed, Aug 28, 2019 at 2:10 PM Nikita Popov nikita.ppv@gmail.com
wrote:On Wed, Aug 28, 2019 at 12:33 PM Nikita Popov nikita.ppv@gmail.com
wrote:Hi internals,
I think it's time to take a look at our existing warnings & notices in
the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only
generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though
there's
room for bikeshedding here...Specifically on undefined variables, the way we deal with them has
little
to do with register_globals. It's behavior you can find in other
dynamic languages (e.g. Perl), and allows for certain code patterns
(which
rely on the automatic creation of a variable whenever it's used in
write
context, and on a default known-in-advance value in case it's used in a
read context). It's fine not to like this behavior or the code
patterns
that commonly rely on it (e.g., @$foo++), but it's intentional and
isn't
related to any historical reasons.This argument makes sense for arrays and objects (and I don't promote
undefined index/property to exceptions for that reason), but I don't
think
it holds any water for simple variables. Writing @$counts[$key]++ is a
lazy
way to count values and avoid ugly boilerplate for if
(isset($counts[$key])) { $counts[$key]++; } else { $counts[$key] = 1; }.
But @$foo++ is just a really bad way of writing either $foo++ or $foo =
Outside of variable variables, the concept of a conditionally defined
variable just doesn't make a lot of sense.This example has nothing to do with arrays. There are many code patterns
in which relying on this behavior makes perfect sense for folks who are a
lot less strictly-minded. For example:foreach (whatever) {
if (sth) {
@$whCount++;
}
}Yes, it may be painful for many eyes that $whCount is not explicitly
initialized, but the above code is perfectly legitimate, warning-free
notice-compliant code since forever. Moreover - this isn't legacy - there
are a lot of folks who appreciate this precise behavior, which is
documented and works as expected for the last 20+ years.Or:
if ($bookCount>0) {
$suffix = 's';
}print "$bookCount book$suffix";
These are just two simple cases I bumped into myself recently. There's an
infinite supply of more of those where these came from.I think many (if not all) of your proposals make sense, but most of
them
make sense as an opt-in - perhaps using something similar to Perl's
strict
mode (which incidentally, changes the way the language treats undefined
variables in exactly the same way). This would also provide a
future-proof
solution for additional similarly-themed proposals (such as strict ops,
etc.).I don't think this is an appropriate use of an opt-in. It's a case where
we can balance language cleanup with backwards compatibility concerns.
Code
that works after this proposal will also work before it, and as such
there
is no danger of ecosystem bifurcation that would need to be addressed
by an
opt-in.Calling this 'cleanup' is opinionated, and avoiding bifurcation by forcing
that opinion on everyone isn't a very good solution for those who have
other opinions. While the opinion that variables must not be used before
being initialized is obviously a valid one - it is just that, one valid
opinion - and there are others. PHP never took this opinion as an
axiomatic requirement (and not because of register_globals) - instead, the
intent was to have a default value for uninitialized variables - a
consistent, documented behavior since the dawn of the language. Can this
be problematic under certain situations? Absolutely. Can it be useful in
other cases? Sure (which is why it's very common). A great deal of folks
both rely on this behavior and *like *it. Those who don't (and there's
plenty of those as well of course) - always had a reasonable solution of
enablingE_STRICT
and enforcing E_STRICT-compliant code. I still think
that having a strict mode (which can encompass strict types, strict ops,
stricter error behavior, etc.) makes a lot of sense and would arguably be
a
superior option for the many folks who prefer a stricter language - but
there's simply no way we can change one of the most fundamental behaviors
of the language and force it down people's throats - not only because it
breaks compatibility, but because it breaks how many people are used to
write their PHP code. Perl provided stricter-liking folks with a solution
in the form of 'use strict;' decades ago; JS did something similar much
more recently. Neither of these created any sort of bifurcation - it's a
simple, sensible solution that has virtually no downsides.While I like Zeev's idea of making it opt-in, I think that a deprecation
path is needed at the very least. I think this has the potential to be an
even bigger issue to deal with than short tags. At least short tags have
been discouraged for a long time. The first short tags RFC would have
probably lead to a delay in upgrading to 8.0. This RFC would pretty much
guarantee never being able to upgrade to 8.0 until we've totally retired
our legacy code base... which will probably be just in time for PHP 28.0 -
assuming the PHP project isn't dead at that point due to this RFC.
I've been told I might not have been totally clear in my post.
My position is that this should be done as an opt-in feature like Zeev as
proposed. If it is not done as an opt-in feature, then I don't think it
should be done at all.
If it is still done, then I think a deprecation path is a must. As
mentioned earlier, this doesn't necessarily mean E_DEPRECATION messages -
warnings will work too. The key is that error logs with more urgency than
notices are created that users can use to track down and fix issues.
Zeev
--
Chase Peeler
chasepeeler@gmail.com
--
Chase Peeler
chasepeeler@gmail.com
My position is that this should be done as an opt-in feature like Zeev as
proposed. If it is not done as an opt-in feature, then I don't think it
should be done at all.
IMO one shouldn't have to opt-in to use common-sense error checking of
engine operations. It's essential to think of the long-term future of
PHP and what makes sense going forward, and to my mind that means things
need to be more intuitive and less prone to mistakes.
Be it Little Jonny Just-Grad who is starting his first proper PHP
project, or the lead engineer of Megacorp, Inc. who is about to write
the first line of the company's next multi-million dollar hit, they
shouldn't need to pile-up on declares at the top of each page just to
make the engine perform as intuitive common sense would dictate.
By the very nature of using @ to suppress error messages, the examples
given are all fully aware that the behaviour they are using is not good
practice.
If the engine was perfectly confident in your use of the statements that
followed it, then it wouldn't display an error that you would need to
suppress in the first place, now would it?
Besides, we have tools available for years now to make this behaviour
more defined:
$counts[$key] = ($counts[$key] ?? 0) + 1;
"If $counts[$key] is not set, use the value 0".
Null Coalescing was explicitly designed to provide for this behaviour.
--
Mark Randall
Hi!
But @$foo++ is just a really bad way of writing either $foo++ or $foo = 1.
If you're working in an environment where you aren't sure if $foo has
been mentioned already or not (ideally, you never have to, practically,
you sometimes are) it's much easier to just do $foo++ than write code to
figure out whether $foo has been already initialized.
Note that while a lot of PHP code is written in IDE-assisted unit-tested
statically-analyzed CI-gated environments, it's not all PHP code.
Sometimes you want to do stuff in quick-n-dirty way, even if it's not
exactly production grade, and PHP traditionally has been excellent
(probably one of the best languages around) for that. I think we
shouldn't abandon that.
--
Stas Malyshev
smalyshev@gmail.com
Hi internals,
https://wiki.php.net/rfc/engine_warnings
This is an absolutely outstanding move and I certainly hope it gets
passed unanimously.
PHP as a whole has traditionally been a language that is insanely
forgiving of errors, in many cases allowing code execution to continue
as if they never even happened, even in utterly egregious cases, and
that is certainly something that has played a part in PHP's reputational
difficulties.
I am extremely happy to see this and other changes underway to reverse
these historic failings. It can only be a good thing for the PHP
ecosystem as a whole to have the engine and core extensions enforce
better protections against bad or potentially buggy code.
It won't be an instant transition, and there will be a lot of hold-outs
on 7.4 who just don't want to deal with it, but as people do eventually
migrate to 8.0, this error-throwing behaviour will force programmers to
improve their code rather than just consign the problem to the /dev/null
error log.
These changes are, no doubt, going to be a painful wake up call for our
friends in the community who are, shall we say, not as focused on the
quality of their code as we (and their customers) would perhaps like
them to be.
For everyone else, it's one more tool to help make us aware of problems,
and prevent those problems from propagating along the stack and
effecting other things.
Bring it on.
--
Mark Randall
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.
While I agree with the reasoning behind this, I think we should be very,
very careful of promoting anything beyond Warning. While it's certainly
true that bugs may be hiding behind Notices and Warnings, it's equally
certain that there is code that is poorly written but has entirely correct
behaviour; for such code, the cure will be worse than the disease, because
an unhandled Error is like suddenly pulling the plug out of the server in
the middle of a transaction.
That's why I was very careful with my undefined constant RFC [1] to first
raise the Notice to a Warning, and leave an appropriate period before
raising to Error. I would be 100% behind raising undefined variable from
Notice to Warning, but think the impact of raising to Error is high enough
that it would risk delaying take-up of PHP 8. Is it too late to raise to
Warning in 7.4, with a clear message that it will be an error in 8.0? That
would give time for people to discover it in rare code paths, get changes
pushed to third-party libraries, etc, before it becomes an unavoidable
error.
[1] https://wiki.php.net/rfc/deprecate-bareword-strings
Rowan Collins
[IMSoP]
Looking at our notice logs, I estimate (fairly roughly) that it would
require about a week's worth of my time to fix these issues in vimeo.com’s
700K LOC codebase (the undefined variables are confined to our views).
IMO it's akin to taking the training wheels off the language – I think the
PHP ecosystem is mature enough to deal with the change.
Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...https://wiki.php.net/rfc/engine_warnings
Regards,
Nikita
Looking at our notice logs, I estimate (fairly roughly) that it would
require about a week's worth of my time to fix these issues
I honestly thought you were posting that as an argument against. A week of resource (plus the accompanying QA impact etc) is a significant investment for many organisations. That's why it has the potential to delay adoption of a new version, and why a long lead-in via deprecation or opt-in is necessary.
Regards,
--
Rowan Collins
[IMSoP]
On Wed, Aug 28, 2019 at 4:56 PM Rowan Collins rowan.collins@gmail.com
wrote:
On 28 August 2019 15:22:22 BST, Matthew Brown matthewmatthew@gmail.com
wrote:Looking at our notice logs, I estimate (fairly roughly) that it would
require about a week's worth of my time to fix these issuesI honestly thought you were posting that as an argument against. A week of
resource (plus the accompanying QA impact etc) is a significant investment
for many organisations. That's why it has the potential to delay adoption
of a new version, and why a long lead-in via deprecation or opt-in is
necessary.
A week for 700KLOC is impressively low.
Many organisations spend more time on deciding whether to upgrade a patch
version of a dependency, and the tooling that vimeo has provided to detect
these issues is technically impressive, and very much usable by other orgs
too.
Marco Pivetta
A week for 700KLOC is impressively low.
Many organisations spend more time on deciding whether to upgrade a
patch
version of a dependency, and the tooling that vimeo has provided to
detect
these issues is technically impressive, and very much usable by other
orgs
too.
I literally have no idea what to take from that response. Some organisations are slow, some have cool workflows, so let's break all the things?
Regards,
--
Rowan Collins
[IMSoP]
A week for 700KLOC is impressively low.
Many organisations spend more time on deciding whether to upgrade a
patch
version of a dependency, and the tooling that vimeo has provided to
detect
these issues is technically impressive, and very much usable by other
orgs
too.I literally have no idea what to take from that response. Some
organisations are slow, some have cool workflows, so let's break all the
things?Regards,
--
Rowan Collins
[IMSoP]
The point is that "some organisations do X" is always used as an excuse for
turning language design mistakes into BC boundaries.
The point is that "some organisations do X" is always used as an excuse
for
turning language design mistakes into BC boundaries.
No. Things that break compatibility are compatibility breaks. It doesn't matter if they were mistakes or fashions, if code will break, it will break. We can't change that by arguing about workflows and tools. Our job is to decide if and how to make those breaks.
So, firstly, we need to agree that their is value to this particular break. I think there probably is, but people may have different opinions.
Secondly, we need to think of a sensible way to introduce it. Is it responsible to put a note in an upgrading page and hope everyone spots it? Is there a way we can flag it more loudly? What is the best time frame to roll it out? Is there a way those who want to get it earlier can do so?
Does that sound reasonable?
Regards,
--
Rowan Collins
[IMSoP]
It's not breaking all the things - it's breaking code that should have been
broken already, but somehow wasn't.
A week for 700KLOC is impressively low.
Many organisations spend more time on deciding whether to upgrade a
patch
version of a dependency, and the tooling that vimeo has provided to
detect
these issues is technically impressive, and very much usable by other
orgs
too.I literally have no idea what to take from that response. Some
organisations are slow, some have cool workflows, so let's break all the
things?Regards,
--
Rowan Collins
[IMSoP]
It's not breaking all the things - it's breaking code that should have
been broken already, but somehow wasn't.
It's still breaking it though.
If you realise that a house is built badly and could be destroyed by a well-aimed kick, you could just give it a kick and say "ah well, not my fault"; or you could warn the owners, offer help in fixing it, and understand that they might be too busy to do it right away.
I don't see why it needs to be such a big deal to ask if this is something we actually need to kick, right now.
Regards,
--
Rowan Collins
[IMSoP]
Kicking a house is a poor analogy IMO - most people don’t upgrade a major
language version without first verifying that their code still works in the
new version.
And the PHP ecosystem is strong – it's possible to find out today if your
code is likely to break (on undefined variables) with both static analysis
tools and runtime error handlers.
On 28 August 2019 17:53:55 BST, Matthew Brown matthewmatthew@gmail.com
wrote:It's not breaking all the things - it's breaking code that should have
been broken already, but somehow wasn't.It's still breaking it though.
If you realise that a house is built badly and could be destroyed by a
well-aimed kick, you could just give it a kick and say "ah well, not my
fault"; or you could warn the owners, offer help in fixing it, and
understand that they might be too busy to do it right away.I don't see why it needs to be such a big deal to ask if this is something
we actually need to kick, right now.Regards,
--
Rowan Collins
[IMSoP]
Kicking a house is a poor analogy IMO - most people don’t upgrade a
major
language version without first verifying that their code still works in
the
new version.
Probably. Most analogies fall down pretty quickly. I just feel like some of the messages on this thread about technical debt are taking great glee in kicking other people's code, rather than offering to help fix it.
Let's talk about how to make this change successful. Let's talk about what tools there are, and what their strengths and limitations are. Let's talk about making people's lives easier now, not punishing them for past mistakes.
Regards,
--
Rowan Tommins
[IMSoP]
It's essentially tech debt, and the language has allowed its users to
accrue a ton of it.
The longer that's allowed (deprecations/warnings prolong the issue in my
opinion) the harder it will be to fix the issues.
On 28 August 2019 15:22:22 BST, Matthew Brown matthewmatthew@gmail.com
wrote:Looking at our notice logs, I estimate (fairly roughly) that it would
require about a week's worth of my time to fix these issuesI honestly thought you were posting that as an argument against. A week of
resource (plus the accompanying QA impact etc) is a significant investment
for many organisations. That's why it has the potential to delay adoption
of a new version, and why a long lead-in via deprecation or opt-in is
necessary.Regards,
--
Rowan Collins
[IMSoP]
Normally every code base has old and new code, some is actively maintained, some is probably third-party maintained, some is unmaintained. Business normally not calculates costs for upgrading, securing, GDPRing old code, so bigger changes always leave some people behind.
I would prefer to write new code with sth like declare(strict_variables=1); or declare(SomeNamespace\Foo:strict_variables=1); That way, people can write new code in a better way, include new libraries and upgrade old code piece by piece without any big pressure.
Regards
Thomas
Matthew Brown matthewmatthew@gmail.com hat am 28. August 2019 um 17:32 geschrieben:
It's essentially tech debt, and the language has allowed its users to
accrue a ton of it.The longer that's allowed (deprecations/warnings prolong the issue in my
opinion) the harder it will be to fix the issues.On 28 August 2019 15:22:22 BST, Matthew Brown matthewmatthew@gmail.com
wrote:Looking at our notice logs, I estimate (fairly roughly) that it would
require about a week's worth of my time to fix these issues
I honestly thought you were posting that as an argument against. A week of
resource (plus the accompanying QA impact etc) is a significant investment
for many organisations. That's why it has the potential to delay adoption
of a new version, and why a long lead-in via deprecation or opt-in is
necessary.
Regards,
--
Rowan Collins
[IMSoP]
FWIW: all the runtime notices in our codebase come from internally-created code.
Requiring declare(strict_variables=1) to get this (better) behaviour punishes future users of PHP for our past mistakes.
Normally every code base has old and new code, some is actively maintained, some is probably third-party maintained, some is unmaintained. Business normally not calculates costs for upgrading, securing, GDPRing old code, so bigger changes always leave some people behind.
I would prefer to write new code with sth like declare(strict_variables=1); or declare(SomeNamespace\Foo:strict_variables=1); That way, people can write new code in a better way, include new libraries and upgrade old code piece by piece without any big pressure.Regards
ThomasMatthew Brown matthewmatthew@gmail.com hat am 28. August 2019 um 17:32 geschrieben:
It's essentially tech debt, and the language has allowed its users to
accrue a ton of it.The longer that's allowed (deprecations/warnings prolong the issue in my
opinion) the harder it will be to fix the issues.On 28 August 2019 15:22:22 BST, Matthew Brown matthewmatthew@gmail.com
wrote:Looking at our notice logs, I estimate (fairly roughly) that it would
require about a week's worth of my time to fix these issues
I honestly thought you were posting that as an argument against. A week of
resource (plus the accompanying QA impact etc) is a significant investment
for many organisations. That's why it has the potential to delay adoption
of a new version, and why a long lead-in via deprecation or opt-in is
necessary.
Regards,
--
Rowan Collins
[IMSoP]
That's a good point, maybe a compromise is this:
<?php // php latest
<?php7 // old behaviour
That way new users can always use <?php, maintainers for old code bases can quickly patch the code with <?php7 to force the old way of engine warnings.
Regards
Thomas
Matthew Brown matthewmatthew@gmail.com hat am 28. August 2019 um 18:21 geschrieben:
FWIW: all the runtime notices in our codebase come from internally-created code.
Requiring declare(strict_variables=1) to get this (better) behaviour punishes future users of PHP for our past mistakes.
Normally every code base has old and new code, some is actively maintained, some is probably third-party maintained, some is unmaintained. Business normally not calculates costs for upgrading, securing, GDPRing old code, so bigger changes always leave some people behind.
I would prefer to write new code with sth like declare(strict_variables=1); or declare(SomeNamespace\Foo:strict_variables=1); That way, people can write new code in a better way, include new libraries and upgrade old code piece by piece without any big pressure.Regards
ThomasMatthew Brown matthewmatthew@gmail.com hat am 28. August 2019 um 17:32 geschrieben:
It's essentially tech debt, and the language has allowed its users to
accrue a ton of it.The longer that's allowed (deprecations/warnings prolong the issue in my
opinion) the harder it will be to fix the issues.On 28 August 2019 15:22:22 BST, Matthew Brown matthewmatthew@gmail.com
wrote:Looking at our notice logs, I estimate (fairly roughly) that it would
require about a week's worth of my time to fix these issues
I honestly thought you were posting that as an argument against. A week of
resource (plus the accompanying QA impact etc) is a significant investment
for many organisations. That's why it has the potential to delay adoption
of a new version, and why a long lead-in via deprecation or opt-in is
necessary.
Regards,
--
Rowan Collins
[IMSoP]
I think we should distinguish two separate problems in the discussion:
- Undeclared local variables in function scope. Some poeple here
think this "lazy" way of coding is actually more productive.
Fixing such places would be straightforward.. except that it may
require patching some legacy 3rd party code.
- Undeclared values, or values of unexpected type, in variables
coming from elsewhere:
- variables used in file scope, e.g. in template files, which are
declared in a different file. - any global variables.
- values in nested arrays, which might have been set in some other
place before they get passed to the current function.
Typically these cases are hard to fix and troubleshoot.
Especially, even if you think you fixed it, there can be some dynamic
conditions that are really hard to test.
E.g. if the username begins with a capital letter, the variable will
be undefined, or a specific array value will be an object instead of a
string..
Ideally such systems should be avoided, or they will need a lot of
try/catch to deal with such problems in the future.
But a lot of legacy code was not written with sufficient sanity
checks, and accepts the occasional or regular notice.
Perhaps is about time for this level of breakage in PHP8. I just want
us to be aware of it.
That's a good point, maybe a compromise is this:
<?php // php latest
<?php7 // old behaviourThat way new users can always use <?php, maintainers for old code bases can quickly patch the code with <?php7 to force the old way of engine warnings.
I am not sure about all the possible implications of this specific
syntax, but I think it would fit into the "editions" idea from the
other thread, if I am not misunderstanding Nikic.
Regards
ThomasMatthew Brown matthewmatthew@gmail.com hat am 28. August 2019 um 18:21 geschrieben:
FWIW: all the runtime notices in our codebase come from internally-created code.
Requiring declare(strict_variables=1) to get this (better) behaviour punishes future users of PHP for our past mistakes.
Normally every code base has old and new code, some is actively maintained, some is probably third-party maintained, some is unmaintained. Business normally not calculates costs for upgrading, securing, GDPRing old code, so bigger changes always leave some people behind.
yes..
I would prefer to write new code with sth like declare(strict_variables=1); or declare(SomeNamespace\Foo:strict_variables=1); That way, people can write new code in a better way, include new libraries and upgrade old code piece by piece without any big pressure.
Regards
ThomasMatthew Brown matthewmatthew@gmail.com hat am 28. August 2019 um 17:32 geschrieben:
It's essentially tech debt, and the language has allowed its users to
accrue a ton of it.The longer that's allowed (deprecations/warnings prolong the issue in my
opinion) the harder it will be to fix the issues.On 28 August 2019 15:22:22 BST, Matthew Brown matthewmatthew@gmail.com
wrote:Looking at our notice logs, I estimate (fairly roughly) that it would
require about a week's worth of my time to fix these issues
I honestly thought you were posting that as an argument against. A week of
resource (plus the accompanying QA impact etc) is a significant investment
for many organisations. That's why it has the potential to delay adoption
of a new version, and why a long lead-in via deprecation or opt-in is
necessary.
Regards,
--
Rowan Collins
[IMSoP]
On Wed, Aug 28, 2019 at 5:22 PM Matthew Brown matthewmatthew@gmail.com
wrote:
Looking at our notice logs, I estimate (fairly roughly) that it would
require about a week's worth of my time to fix these issues in vimeo.com’s
700K LOC codebase (the undefined variables are confined to our views).
Can you elaborate a bit about how you generally deal with notices in
vimeo.com - are you generally aiming to be notice-free? Or is that log
collecting a huge amount of messages?
Zeev
We log 1 in every 1000 notices, and yes - being notice-free is a goal –
though not one with any particular timeline at the moment, because we can
just ignore the problem. I look forward to not being able to ignore the
problem.
On Wed, Aug 28, 2019 at 5:22 PM Matthew Brown matthewmatthew@gmail.com
wrote:Looking at our notice logs, I estimate (fairly roughly) that it would
require about a week's worth of my time to fix these issues in vimeo.com
’s
700K LOC codebase (the undefined variables are confined to our views).Can you elaborate a bit about how you generally deal with notices in
vimeo.com - are you generally aiming to be notice-free? Or is that log
collecting a huge amount of messages?Zeev
On Wed, Aug 28, 2019 at 8:20 PM Matthew Brown matthewmatthew@gmail.com
wrote:
We log 1 in every 1000 notices, and yes - being notice-free is a goal –
though not one with any particular timeline at the moment, because we can
just ignore the problem. I look forward to not being able to ignore the
problem.
When was this goal set? Was there effort that went into it?
My point is this:
In a codebase where being notice-free isn't a goal - and/or where code
patterns that rely on the documented behavior of how PHP variables are
initialized as well as behave in read scenarios (with or without the
silence operator) - I think you're going to find a lot of such instances,
probably more so than in a company that made an informed decision to not
allow it and gradually work to remove existing code that uses it. For
many, this is not considered technical debt - but rather - using the
language as intended. Using the language in a way that is sanctioned and
considered valid - alongside other ways which are also considered valid
(e.g. a notice-free codebase).
While I understand what you're saying when you say that you look forward to
not being able to ignore the problem, it sounds like a fairly weak argument
for forcing everyone else - many of whom don't consider this to be a
problem at all - to change their code. Instead, if this bothers you, make
an informed decision to change - there's enough tooling to do that today
with reasonable effort. Or support the ability to flip a switch that will
granularly force you to fix these particular issues. Forcing all users to
work in a certain way, because some of the users who want to work that way
can't bring themselves to do it - doesn't sound very sensible IMHO.
I was hoping that the glaring obviousness of how other languages tackled
similar issues (Perl, JS) would go a longer way. It should.
Zeev
On Wed, Aug 28, 2019 at 8:20 PM Matthew Brown matthewmatthew@gmail.com
wrote:We log 1 in every 1000 notices, and yes - being notice-free is a goal –
though not one with any particular timeline at the moment, because we can
just ignore the problem. I look forward to not being able to ignore the
problem.When was this goal set? Was there effort that went into it?
My point is this:
In a codebase where being notice-free isn't a goal - and/or where code
patterns that rely on the documented behavior of how PHP variables are
initialized as well as behave in read scenarios (with or without the
silence operator) - I think you're going to find a lot of such instances,
probably more so than in a company that made an informed decision to not
allow it and gradually work to remove existing code that uses it. For
many, this is not considered technical debt - but rather - using the
language as intended. Using the language in a way that is sanctioned and
considered valid - alongside other ways which are also considered valid
(e.g. a notice-free codebase).
For the record, I don't view undeclared variable notices as technical debt
either. I've engaged in that discussion at other points because I think
this is a bad move even if it is considered technical debt. My personal
opinion is that I like the flexibility of the language in this matter. I
initialize my variables most of the time anyway, but, I don't think every
other PHP developer should be forced to do that just because I like to do
it.
While I understand what you're saying when you say that you look forward to
not being able to ignore the problem, it sounds like a fairly weak argument
for forcing everyone else - many of whom don't consider this to be a
problem at all - to change their code. Instead, if this bothers you, make
an informed decision to change - there's enough tooling to do that today
with reasonable effort. Or support the ability to flip a switch that will
granularly force you to fix these particular issues. Forcing all users to
work in a certain way, because some of the users who want to work that way
can't bring themselves to do it - doesn't sound very sensible IMHO.
My feelings exactly. What benefits are we getting by FORCING everyone to
follow this policy that individual users/companies/development teams can't
already gain by just making it a policy and using 3rd party tools to
enforce it? What HARM continues to exist in the language if undeclared
variables only generate a notice - given the fact that how PHP handles
undeclared variables is will documented and, in my opinion, actually a
feature of the language?
I was hoping that the glaring obviousness of how other languages tackled
similar issues (Perl, JS) would go a longer way. It should.Zeev
--
Chase Peeler
chasepeeler@gmail.com
Javascript has treated undefined variables as a catchable exceptions since
(I think?) forever. Perl is the only other language I know that allows them.
I've written code in a lot of different languages. Many of those languages
(most notably Standard ML) forced me to think about how exactly data flowed
through my program. PHP, on the other hand, doesn't demand anything like as
much work. This means its developers often don't improve much either, which
ultimately this harms the language's reputation as former PHP developers
discover their bad habits don't translate well to other languages.
With this change we can make it harder for people to write bad code, which
I think will result in existing PHP users becoming better developers.
On Wed, Aug 28, 2019 at 8:20 PM Matthew Brown matthewmatthew@gmail.com
wrote:We log 1 in every 1000 notices, and yes - being notice-free is a goal –
though not one with any particular timeline at the moment, because we can
just ignore the problem. I look forward to not being able to ignore the
problem.When was this goal set? Was there effort that went into it?
My point is this:
In a codebase where being notice-free isn't a goal - and/or where code
patterns that rely on the documented behavior of how PHP variables are
initialized as well as behave in read scenarios (with or without the
silence operator) - I think you're going to find a lot of such instances,
probably more so than in a company that made an informed decision to not
allow it and gradually work to remove existing code that uses it. For
many, this is not considered technical debt - but rather - using the
language as intended. Using the language in a way that is sanctioned and
considered valid - alongside other ways which are also considered valid
(e.g. a notice-free codebase).While I understand what you're saying when you say that you look forward
to not being able to ignore the problem, it sounds like a fairly weak
argument for forcing everyone else - many of whom don't consider this to be
a problem at all - to change their code. Instead, if this bothers you,
make an informed decision to change - there's enough tooling to do that
today with reasonable effort. Or support the ability to flip a switch that
will granularly force you to fix these particular issues. Forcing all
users to work in a certain way, because some of the users who want to work
that way can't bring themselves to do it - doesn't sound very sensible IMHO.I was hoping that the glaring obviousness of how other languages tackled
similar issues (Perl, JS) would go a longer way. It should.Zeev
Hi!
Javascript has treated undefined variables as a catchable exceptions since
(I think?) forever.
Which seems to be why I open a random Javascript file in our codebase
and see this:
var wikibase = wikibase || {};
wikibase.queryService = wikibase.queryService || {};
wikibase.queryService.ui = wikibase.queryService.ui || {};
wikibase.queryService.ui.toolbar = wikibase.queryService.toolbar || {};
wikibase.queryService.ui.toolbar.Actionbar = ...
(not my code but I've seen it a lot)
IMHO, this is language getting in a way and people writing boilerplate
to avoid "service" that is not actually needed.
much work. This means its developers often don't improve much either, which
I don't think PHP should be a language that "builds character" by
forcing people to do more work than it's necessary for them, in order
for them to "improve". I think it should be as easy as possible, and if
somebody wants to learn how the bits move, one can always pick up a good
book or go to a Coursera course, etc.
--
Stas Malyshev
smalyshev@gmail.com
If we want PHP to be as easy as possible then $nullref->bar(), $foo->someUndefined(), new UndefinedClass etc shouldn’t be exceptions either - they can just be notices.
Hi!
Javascript has treated undefined variables as a catchable exceptions since
(I think?) forever.Which seems to be why I open a random Javascript file in our codebase
and see this:var wikibase = wikibase || {};
wikibase.queryService = wikibase.queryService || {};
wikibase.queryService.ui = wikibase.queryService.ui || {};
wikibase.queryService.ui.toolbar = wikibase.queryService.toolbar || {};wikibase.queryService.ui.toolbar.Actionbar = ...
(not my code but I've seen it a lot)
IMHO, this is language getting in a way and people writing boilerplate
to avoid "service" that is not actually needed.much work. This means its developers often don't improve much either, which
I don't think PHP should be a language that "builds character" by
forcing people to do more work than it's necessary for them, in order
for them to "improve". I think it should be as easy as possible, and if
somebody wants to learn how the bits move, one can always pick up a good
book or go to a Coursera course, etc.--
Stas Malyshev
smalyshev@gmail.com
If we want PHP to be as easy as possible then $nullref->bar(), $foo->someUndefined(),
new UndefinedClass etc shouldn’t be exceptions either - they can just be notices.
That's very different. Note that this code doesn't even generate a notice:
$x = null;
var_dump($x+1);
I'm joining the thread to point out another way to avoid the notice in hopes that
this way doesn't get deprecated or somesuch:
$temp =& $never_defined; // No notice :)
$temp++; // Happily becomes 1 if $never_defined wasn't defined
unset($temp); // so we don't unintentionally make more changes with $temp later
Our code predates "??" and we use the above boilerplate in many, many places, but
it isn't boilerplate enough to easily search and replace.
- Todd
Hi!
Javascript has treated undefined variables as a catchable exceptions since
(I think?) forever.Which seems to be why I open a random Javascript file in our codebase
and see this:var wikibase = wikibase || {};
wikibase.queryService = wikibase.queryService || {};
wikibase.queryService.ui = wikibase.queryService.ui || {};
wikibase.queryService.ui.toolbar = wikibase.queryService.toolbar || {};wikibase.queryService.ui.toolbar.Actionbar = ...
(not my code but I've seen it a lot)
IMHO, this is language getting in a way and people writing boilerplate
to avoid "service" that is not actually needed.much work. This means its developers often don't improve much either, which
I don't think PHP should be a language that "builds character" by
forcing people to do more work than it's necessary for them, in order
for them to "improve". I think it should be as easy as possible, and if
somebody wants to learn how the bits move, one can always pick up a good
book or go to a Coursera course, etc.--
Stas Malyshev
smalyshev@gmail.com
Hi!
If we want PHP to be as easy as possible then $nullref->bar(),
$foo->someUndefined(), new UndefinedClass etc shouldn’t be exceptions
either - they can just be notices.
I don't see how it follows. Calling unknown method does not have natural
default - if I tell you "would you please do abracadabra" you can't just
do something random and consider it done - you should tell me "what do
you mean by that? Please explain what you want me to do".
However, if I tell you "here's an apple, add it to your pocket", then
there's a natural way of knowing how many apples is in your pocket for
every state of your pocket before - if your pocket was empty, it now has
one apple, if it had apples before, now it has one more. I don't need to
explain you what to do when your pocket is empty and when it's not
separately - you can guess intuitively what should happen in each case
and you'd be 100% right always.
That's the natural difference between $foo++ and foo() - in the former
case, you know what should happen in any case (including when $foo is
initialized to a non-numeric value - then you error out), in the
latter, if foo() is not defined, there's no natural way to go but to
error out. There's a crucial difference here because variables are
containers, not actors. Dealing with an empty container has natural
semantics (in some cases at least), dealing with non-existing actor does
not.
Stas Malyshev
smalyshev@gmail.com
This is where I think PHP may have broken us a little.
I just asked a few non-PHP developers here what they expect "(function () {
$a++; })()" to do, and they agreed it would be some sort of error. Got the
same answer for "(function () { $a->bar = 5; })() ".
Indeed, anyone who's used another C-like language (JS, TS, Java, C# etc) is
used to these things being errors, so it can be disorientating to see them
treated as anything else by PHP (it was disorientating for me, at least).
On Wed, 28 Aug 2019 at 18:06, Stanislav Malyshev smalyshev@gmail.com
wrote:
Hi!
If we want PHP to be as easy as possible then $nullref->bar(),
$foo->someUndefined(), new UndefinedClass etc shouldn’t be exceptions
either - they can just be notices.I don't see how it follows. Calling unknown method does not have natural
default - if I tell you "would you please do abracadabra" you can't just
do something random and consider it done - you should tell me "what do
you mean by that? Please explain what you want me to do".
However, if I tell you "here's an apple, add it to your pocket", then
there's a natural way of knowing how many apples is in your pocket for
every state of your pocket before - if your pocket was empty, it now has
one apple, if it had apples before, now it has one more. I don't need to
explain you what to do when your pocket is empty and when it's not
separately - you can guess intuitively what should happen in each case
and you'd be 100% right always.That's the natural difference between $foo++ and foo() - in the former
case, you know what should happen in any case (including when $foo is
initialized to a non-numeric value - then you error out), in the
latter, if foo() is not defined, there's no natural way to go but to
error out. There's a crucial difference here because variables are
containers, not actors. Dealing with an empty container has natural
semantics (in some cases at least), dealing with non-existing actor does
not.Stas Malyshev
smalyshev@gmail.com
Hi!
This is where I think PHP may have broken us a little.
I think it's in no way "broken" to be able to easily match expectations,
like $foo++ always do what you meant without clunky boilerplate.
Also, if you think PHP is the only language I program in daily (and I
mean every day, except some weekends and vacations maybe) you're wrong
:) I have something to compare to, so what I say some things are easier
in PHP that's because I actually compared.
I just asked a few non-PHP developers here what they expect "(function
() { $a++; })()" to do, and they agreed it would be some sort of error.
Got the same answer for "(function () { $a->bar = 5; })() ".
I see absolutely no reason for it. Maybe if you're a Java programmer who
never saw non-statically-typed non-B&D language - but that's not a
virtue we should be striving to emulate. If we have a tool that already
does things better and some people don't even know such tools are
possible, we should educate them, not break our tools so it would be
more comfortable fit to their experience.
Indeed, anyone who's used another C-like language (JS, TS, Java, C# etc)
is used to these things being errors, so it can be disorientating to see
I don't think having things just work instead of usual boilerplate that
you have to declare everything upfront and repeat even obvious things
numerous times is "disorienting" in any way. If you check how languages
that are alive evolve (like Java or C++, C is mostly fossilized these
days), even strict ones, you see they support more and more intuitive
approaches - like auto variables for example - which make things easier.
Because human should spend time thinking, not figuring out how to
satisfy a dumb compiler. That's the direction we should be moving to.
Not adding more errors and boilerplate in clear cases like $foo++.
--
Stas Malyshev
smalyshev@gmail.com
$foo++ becoming 1 when $foo is undefined is not intuitive to me.
To take a very trivial example, that behaviour causes “for ($i = 0; $i < 10; $I++) {}” to loop indefinitely.
Hi!
This is where I think PHP may have broken us a little.
I think it's in no way "broken" to be able to easily match expectations,
like $foo++ always do what you meant without clunky boilerplate.
Also, if you think PHP is the only language I program in daily (and I
mean every day, except some weekends and vacations maybe) you're wrong
:) I have something to compare to, so what I say some things are easier
in PHP that's because I actually compared.I just asked a few non-PHP developers here what they expect "(function
() { $a++; })()" to do, and they agreed it would be some sort of error.
Got the same answer for "(function () { $a->bar = 5; })() ".I see absolutely no reason for it. Maybe if you're a Java programmer who
never saw non-statically-typed non-B&D language - but that's not a
virtue we should be striving to emulate. If we have a tool that already
does things better and some people don't even know such tools are
possible, we should educate them, not break our tools so it would be
more comfortable fit to their experience.Indeed, anyone who's used another C-like language (JS, TS, Java, C# etc)
is used to these things being errors, so it can be disorientating to seeI don't think having things just work instead of usual boilerplate that
you have to declare everything upfront and repeat even obvious things
numerous times is "disorienting" in any way. If you check how languages
that are alive evolve (like Java or C++, C is mostly fossilized these
days), even strict ones, you see they support more and more intuitive
approaches - like auto variables for example - which make things easier.
Because human should spend time thinking, not figuring out how to
satisfy a dumb compiler. That's the direction we should be moving to.
Not adding more errors and boilerplate in clear cases like $foo++.--
Stas Malyshev
smalyshev@gmail.com
Hi!
$foo++ becoming 1 when $foo is undefined is not intuitive to me.
I guess we have different intuition.
To take a very trivial example, that behaviour causes “for ($i = 0;
$i < 10; $I++) {}” to loop indefinitely.
This is rather shallow issue, which any modern IDE would highlight for
you in about 0.5 seconds. No need to change the language for that.
Frankly, I have hard time remembering when any of such typos ever get
past IDE check since I started using IDEs.
And, of course, it's completely obvious issue - you could as well forget
to write $i++ at all, or write $j++ and have $j defined somewhere...
there's a lot of artificial scenarios one could think of. No reason to
change rules of the whole language because of it.
--
Stas Malyshev
smalyshev@gmail.com
On Thu, Aug 29, 2019, 12:33 AM Stanislav Malyshev smalyshev@gmail.com
wrote:
Hi!
$foo++ becoming 1 when $foo is undefined is not intuitive to me.
I guess we have different intuition.
To take a very trivial example, that behaviour causes “for ($i = 0;
$i < 10; $I++) {}” to loop indefinitely.
This is rather shallow issue, which any modern IDE would highlight for
you in about 0.5 seconds. No need to change the language for that.
Frankly, I have hard time remembering when any of such typos ever get
past IDE check since I started using IDEs.
And, of course, it's completely obvious issue - you could as well forget
to write $i++ at all, or write $j++ and have $j defined somewhere...
there's a lot of artificial scenarios one could think of. No reason to
change rules of the whole language because of it.
Can you point me to an IDE that runs on the server?
I think you are mixing static analysis error with dynamic runtime analysis.
IDE can't point to an error it doesn't know about(which I didn't code using
IDE but use notepad, where I didn't run full test before publishing to
production).
I don't think it makes sense to allow the language be a home of "anything
goes, no innovation".
A language without specification.
On Wed, Aug 28, 2019 at 10:28 PM Matthew Brown matthewmatthew@gmail.com
wrote:
Javascript has treated undefined variables as a catchable exceptions since
(I think?) forever. Perl is the only other language I know that allows them.
That isn't the point (I alluded to the fact that JS dealt with something
similar but not quite the same in my first mention of it). The point is
that when they wanted to make behavior around variables stricter than
what it was originally, they didn't simply change it - they added an opt-in
strict mode.
I've written code in a lot of different languages. Many of those languages
(most notably Standard ML) forced me to think about how exactly data flowed
through my program. PHP, on the other hand, doesn't demand anything like as
much work. This means its developers often don't improve much either, which
ultimately this harms the language's reputation as former PHP developers
discover their bad habits don't translate well to other languages.With this change we can make it harder for people to write bad code, which
I think will result in existing PHP users becoming better developers.
With this change we're taking away from people - including very informed
developers - the ability to use it as intended (one form of it that is).
There's a reason there's a wide selection of languages available, and that
different people have different language preferences. Personally, I can't
stand ML - and I find myself a lot more productive in other languages. But
I'm not going to campaign to change ML into something different because it
doesn't fit my programming/thinking style.
Granted - PHP is orders of magnitude more popular and widely used than ML,
and we need to figure out ways to make this huge audience content -
including many who aren't happy with its behavior (whether it's because
they made an uninformed decision choosing it, or because it wasn't their
choice at all, or because they actually do like the language and would be
happy to use it if only it had X, Y and Z). But it shouldn't be at the
expense of others. Exactly like Perl and JS did it when they decided to
offer a stricter execution model.
Zeev
Zeev,
When you write code, in a "productive" way that you mention, it's perfectly
fine if you write it for you and for now.
But most often, we write code for the future generations of developers that
could be less skilled, for the future you that might have less context.
Also, code will evolve in time and bugs will eventually apear. In my
opinion and maybe you can agree, some of these bugs could be avoided if
variable definition before reading would be enforced.
Yes, it costs us more time to do it and productivity might be decreased by
1-2%.
For most of the developers and businesses using PHP, that is a trade they
want to enforce but can't or does not know how to do it.
I am for a default with more things enforced and maybe only allowed them
based on declares, not the other way around.
Regards,
Alex
On Wed, Aug 28, 2019 at 10:28 PM Matthew Brown matthewmatthew@gmail.com
wrote:Javascript has treated undefined variables as a catchable exceptions
since
(I think?) forever. Perl is the only other language I know that allows
them.That isn't the point (I alluded to the fact that JS dealt with something
similar but not quite the same in my first mention of it). The point is
that when they wanted to make behavior around variables stricter than
what it was originally, they didn't simply change it - they added an opt-in
strict mode.I've written code in a lot of different languages. Many of those languages
(most notably Standard ML) forced me to think about how exactly data
flowed
through my program. PHP, on the other hand, doesn't demand anything like
as
much work. This means its developers often don't improve much either,
which
ultimately this harms the language's reputation as former PHP developers
discover their bad habits don't translate well to other languages.With this change we can make it harder for people to write bad code,
which
I think will result in existing PHP users becoming better developers.With this change we're taking away from people - including very informed
developers - the ability to use it as intended (one form of it that is).
There's a reason there's a wide selection of languages available, and that
different people have different language preferences. Personally, I can't
stand ML - and I find myself a lot more productive in other languages. But
I'm not going to campaign to change ML into something different because it
doesn't fit my programming/thinking style.Granted - PHP is orders of magnitude more popular and widely used than ML,
and we need to figure out ways to make this huge audience content -
including many who aren't happy with its behavior (whether it's because
they made an uninformed decision choosing it, or because it wasn't their
choice at all, or because they actually do like the language and would be
happy to use it if only it had X, Y and Z). But it shouldn't be at the
expense of others. Exactly like Perl and JS did it when they decided to
offer a stricter execution model.Zeev
Am 29.08.2019 um 08:22 schrieb Alexandru Pătrănescu drealecs@gmail.com:
When you write code, in a "productive" way that you mention, it's perfectly
fine if you write it for you and for now.But most often, we write code for the future generations of developers that
could be less skilled, for the future you that might have less context.
Also, code will evolve in time and bugs will eventually apear. In my
opinion and maybe you can agree, some of these bugs could be avoided if
variable definition before reading would be enforced.
... and that's why Zeev suggests a strict mode for people who want it that way.
Side-note: Which brings us back to the discussion about the downsides of language modes but as similar topics keep on popping up (although by the same people) you are slowly convincing me that going down that road is the best compromise.
For most of the developers and businesses using PHP, that is a trade they
want to enforce but can't or does not know how to do it.
That "most developers" is highly subjective depending on who you ask.
And yes, you can easily turn undefined variables into exceptions right now (even globally), just use
set_error_handler(function($errno, $errstr) {
if (preg_match('/^Undefined variable/', $errstr))
throw new Exception($errstr);
return false;
}, E_NOTICE);
I am for a default with more things enforced and maybe only allowed them
based on declares, not the other way around.
Breaking code first and making migration harder instead of offering a clean migration path where developers opt-in to a new mode.
- Chris
On Thu, 29 Aug 2019 at 08:28, Christian Schneider cschneid@cschneid.com
wrote:
Side-note: Which brings us back to the discussion about the downsides of
language modes but as similar topics keep on popping up (although by the
same people) you are slowly convincing me that going down that road is the
best compromise.
Is there any technical reason PHP can't go the transpiler route? Let
everyone experiment with their own preferred changes, and pull the best
ideas, once proven, into core PHP?
Peter
Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...https://wiki.php.net/rfc/engine_warnings
Regards,
Nikita
It seems quite clear to me that the question of the "undefined variable"
error is contentious. As such, I have decided to split it off into a
separate section in the proposal, that will be voted separately from the
rest. I will offer the choice of throwing an Error exception (as originally
proposed), throwing a warning or keeping the existing notice.
Reading this discussion has been disappointing and somewhat disillusioning.
I can understand and appreciate the concern for legacy code. But seeing the
use of undefined variables espoused as a legitimate programming style, that
just makes me sad.
Regards,
Nikita
On Wed, Aug 28, 2019 at 11:33 AM Nikita Popov nikita.ppv@gmail.com
wrote:Reading this discussion has been disappointing and somewhat disillusioning.
I can understand and appreciate the concern for legacy code. But seeing the
use of undefined variables espoused as a legitimate programming style, that
just makes me sad.
Nikita,
It's really awkward that anybody would be under the illusion that the way
the language always behaved, consistently and well-documented pretty much
from the its inception, is somehow a bug that everybody agrees on that's
just waiting for someone to come over and fix it. Do you really think that
if there was widespread consensus that this wasn't a legitimate programming
style, we'd have to wait for 20 years for folks to propose to change/remove
it? This isn't short tags - this is fundamental language behavior, that
indeed isn't even documented anywhere as a 'bad thing you must avoid'.
There are commonly used code templates that rely on it, and do it in a way
many would find perfectly reasonable. Many do, and always did consider it
as a legitimate programming style. Many others do not - which is why we
added capabilities ages ago (from the get go, for all practical purposes)
that allow users to employ a much stricter programming style by enabling
notices. We never, ever, at any point, considered this behavior to be
'legacy'. It's a language feature, that you can choose whether you want to
use or not (and perhaps we can get better at that).
The fact that PHP isn't supposed to be a strict language is repeatedly
confused with exclusive concern for 'legacy code' as of late. Yes, the
complete disregard for backwards compatibility that appears to be the most
widely accepted POV on internals is disconcerting - but much more
importantly - just because one doesn't like a certain fundamental part of
the language, doesn't make the use of it 'legacy'. If anything, it perhaps
means that said person who chose the language made the wrong choice (there
are plenty of other choices to choose from), and they're now campaigning to
change it to fit the image of what they think it should be that they have
in mind.
With that said - I think it does make sense to try and come up with ways to
cater to those who prefer a stricter language, and in this particular case
- something that's a bit more aggressive than notices. But if there's
something sad about this, it's the insistence to always frame the
discussion as a zero sum game - instead of trying to find solutions that
cater to a wider audiences. It's time to accept that the composition of
PHP users is a lot wider than what's represented on internals, and it's
certainly not everyone's opinion that the current language is in dire need
of being rescued.
PHP can be improved for those who find it lacking, without harming those
who are in fact happy with the way it currently is. We should start
looking for such solutions, instead of each just trying to 'win for their
own camp', putting things to a vote hoping to subjugate the other.
Zeev
I'm sorry, but if you seriously believe doing something that generates a
notice (or warning, or error, ...) is not a bug - you're delusional.
That is the very definition of a bug and notices/warnings/errors etc.
are the mechanism the language uses to report these bugs to the
developer. If doing X has been generating a notice for 20 years, then
doing X is wrong and a bug, period. Why would there even be a notice if
the language itself doesn't consider what you're doing to be buggy? What
is the purpose of notices then? I really don't understand how anyone
could contest this.
It's really awkward that anybody would be under the illusion that the way
the language always behaved, consistently and well-documented pretty much
from the its inception, is somehow a bug that everybody agrees on that's
just waiting for someone to come over and fix it.
Le 29 août 2019 à 13:33, Aegir Leet via internals internals@lists.php.net a écrit :
I'm sorry, but if you seriously believe doing something that generates a
notice (or warning, or error, ...) is not a bug - you're delusional.
No, what you think is not at all how notices were designed. From the manual (https://www.php.net/errorfunc.constants https://www.php.net/errorfunc.constants):
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.
One can discuss whether unitialised variables should trigger a notice or a warning. But let us respect the semantics of the language features.
—Claude
I know what the manual says about notices. But I don't agree with interpreting "could happen in the normal course of running a script" as "it's perfectly fine if this part of your code triggers a notice consistently and every time it goes down this particular code path". Rather, I've always interpreted this as "under certain, rare, unforeseen circumstances, your code could generate a notice here, probably because of something that is outside of your control".
That's how I've always treated them at least.
Regardless of the exact semantics, don't you think a program that generates a constant stream of notices is a bit strange? That sounds like something everyone would naturally want to avoid. You don't drive your car with the check engine light permanently on and say "this is fine", right?
Le 29 août 2019 à 13:33, Aegir Leet via internals <internals@lists.php.netmailto:internals@lists.php.net> a écrit :
I'm sorry, but if you seriously believe doing something that generates a
notice (or warning, or error, ...) is not a bug - you're delusional.
No, what you think is not at all how notices were designed. From the manual (https://www.php.net/errorfunc.constants):
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.
One can discuss whether unitialised variables should trigger a notice or a warning. But let us respect the semantics of the language features.
—Claude
On Thu, Aug 29, 2019 at 4:02 PM Aegir Leet via internals <
internals@lists.php.net> wrote:
I know what the manual says about notices. But I don't agree with
interpreting "could happen in the normal course of running a script" as
"it's perfectly fine if this part of your code triggers a notice
consistently and every time it goes down this particular code path".
Rather, I've always interpreted this as "under certain, rare, unforeseen
circumstances, your code could generate a notice here, probably because of
something that is outside of your control".That's how I've always treated them at least.
And that's entirely within your right to do so - but what the manual says
is accurate. Calling me delusional in my interpretation of it is somewhat
awkward (to put it mildly), I have a pretty good idea of why we added the
different error levels - I wrote much of it myself.
The whole point of having notices as something that's separate from
warnings is that they have different semantics, and that semantics is
captured very accurately in the manual. They are used to mark issues which
may be problems, but may also be perfectly fine (unlike warnings, which
generally speaking mean that something bad happened, but not bad enough to
halt execution). Notices were meant to help you implement a more strict
style of coding, and they may help you catch certain types of bugs, but you
can have perfectly working, bug-free code that generates notices.
Regardless of the exact semantics, don't you think a program that generates
a constant stream of notices is a bit strange? That sounds like something
everyone would naturally want to avoid. You don't drive your car with the
check engine light permanently on and say "this is fine", right?
Except you can purposely turn off this 'check engine' light, never to see
it again if you choose to. And that it's really not at all similar to
'check engine', but a lot closer to 'check cleaning fluid', or even 'clean
windshield' (if cars had a dashboard light for that). Even that is not a
good analogy - as folks often actually purposely write code that generates
notices (which would be purposely hidden, either by error_reporting setting
or using @) that is 100% bug-free and working as intended. So no, there's
nothing strange about it if you buy into that approach. If you don't (and
I know you don't) - that's absolutely fine - it's up to you.
Zeev
On Thu, Aug 29, 2019 at 4:02 PM Aegir Leet via internals <
internals@lists.php.net> wrote:I know what the manual says about notices. But I don't agree with
interpreting "could happen in the normal course of running a script" as
"it's perfectly fine if this part of your code triggers a notice
consistently and every time it goes down this particular code path".
Rather, I've always interpreted this as "under certain, rare, unforeseen
circumstances, your code could generate a notice here, probably because
of
something that is outside of your control".That's how I've always treated them at least.
And that's entirely within your right to do so - but what the manual says
is accurate. Calling me delusional in my interpretation of it is somewhat
awkward (to put it mildly), I have a pretty good idea of why we added the
different error levels - I wrote much of it myself.The whole point of having notices as something that's separate from
warnings is that they have different semantics, and that semantics is
captured very accurately in the manual. They are used to mark issues which
may be problems, but may also be perfectly fine (unlike warnings, which
generally speaking mean that something bad happened, but not bad enough to
halt execution). Notices were meant to help you implement a more strict
style of coding, and they may help you catch certain types of bugs, but you
can have perfectly working, bug-free code that generates notices.Regardless of the exact semantics, don't you think a program that generates
a constant stream of notices is a bit strange? That sounds like something
everyone would naturally want to avoid. You don't drive your car with the
check engine light permanently on and say "this is fine", right?Except you can purposely turn off this 'check engine' light, never to see
it again if you choose to. And that it's really not at all similar to
'check engine', but a lot closer to 'check cleaning fluid', or even 'clean
windshield' (if cars had a dashboard light for that). Even that is not a
good analogy - as folks often actually purposely write code that generates
notices (which would be purposely hidden, either by error_reporting setting
or using @) that is 100% bug-free and working as intended. So no, there's
nothing strange about it if you buy into that approach. If you don't (and
I know you don't) - that's absolutely fine - it's up to you.Zeev
I just wanted to bring up a few other points. First, as I think Stanislav
has done a good job of pointing out, the flexibility of PHP is one of its
greatest features. The nice thing about a flexible and forgiving language
is that you can always put additional things in place on top of it to make
it more strict and rigid if you want. Once you force a language to be
strict and rigid, however, it's much harder, if not impossible, to add back
in flexibility.
A lot of my emails on this thread have been focused on the burden to
developers caused by the BC break. While I still think that is an important
consideration, it distracted me from my initial view which was we shouldn't
do this because it's just a bad idea. I understand all of the arguments for
enforcing variable initialization. I agree with most of them as well.
However, I think there are a myriad of ways that individuals and teams can
do that enforcement without forcing it on every single developer whether
they want it or not.
A lot of comparisons have been made to other languages. I do a lot of work
with javascript and I have a good amount of experience with c# as well.
I've used many other languages at times (c, c++, java, perl, ruby, etc.) as
well. In c#, you don't have to initialize your variables - you have to
declare them. Some types, like ints, are automatically initialized to 0
unless explicitly initialized to something else. PHP doesn't require you to
declare variables. So, while c# might require "int i; i++;" you can achieve
the same thing in PHP with "$i++;" - neither one requires an explicit
initialization.
A few people have referred to the fact that I have instances of undeclared
variables as technical debt. As I said earlier, I've engaged in these
discussions because I don't think just calling something technical debt
should be justification for a change. The fact that a large number of
developers might have technical debt in a certain area should be considered
when weighing the pros and cons of a breaking change. That being said, I do
NOT consider such code to be technical debt or bad code that needs to be
fixed. The only way it becomes either of those if with the implementation
of this RFC. It's a bit disingenuous to tell developers they have to make
large changes, and when they push back, tell them it's their fault for
accruing so much technical debt - when it's the RFC itself that actually
causes the technical debt to begin with! *I will no longer engage in
conversations on this topic that relate to how you think my company should
conduct business or prioritize development. *
Finally, since people seem hell bent on turning PHP into a language that
operates like all the others, instead of letting it keep its unique
qualities that make it great and different, I asked a c# developer I know
about how Microsoft deals with breaking changes. Here was his response:
"I’ve never heard of a breaking change when new versions of C# are
released. There are occasionally breaking changes when upgrading to a new
version of .NET, but they always (as far as I’m aware) have a way to
prevent the change from breaking anything by adding a parameter the app’s
configuration."
--
Chase Peeler
chasepeeler@gmail.com
I don’t think it’s helpful to compare C#’s BC policies to PHP’s. C# is used today mostly as its architect intended at its founding. PHP, having transitioned from a templating system to a fully-fledged language, is used quite differently.
On Thu, Aug 29, 2019 at 4:02 PM Aegir Leet via internals <
internals@lists.php.net> wrote:I know what the manual says about notices. But I don't agree with
interpreting "could happen in the normal course of running a script" as
"it's perfectly fine if this part of your code triggers a notice
consistently and every time it goes down this particular code path".
Rather, I've always interpreted this as "under certain, rare, unforeseen
circumstances, your code could generate a notice here, probably because
of
something that is outside of your control".That's how I've always treated them at least.
And that's entirely within your right to do so - but what the manual says
is accurate. Calling me delusional in my interpretation of it is somewhat
awkward (to put it mildly), I have a pretty good idea of why we added the
different error levels - I wrote much of it myself.The whole point of having notices as something that's separate from
warnings is that they have different semantics, and that semantics is
captured very accurately in the manual. They are used to mark issues which
may be problems, but may also be perfectly fine (unlike warnings, which
generally speaking mean that something bad happened, but not bad enough to
halt execution). Notices were meant to help you implement a more strict
style of coding, and they may help you catch certain types of bugs, but you
can have perfectly working, bug-free code that generates notices.Regardless of the exact semantics, don't you think a program that generates
a constant stream of notices is a bit strange? That sounds like something
everyone would naturally want to avoid. You don't drive your car with the
check engine light permanently on and say "this is fine", right?Except you can purposely turn off this 'check engine' light, never to see
it again if you choose to. And that it's really not at all similar to
'check engine', but a lot closer to 'check cleaning fluid', or even 'clean
windshield' (if cars had a dashboard light for that). Even that is not a
good analogy - as folks often actually purposely write code that generates
notices (which would be purposely hidden, either by error_reporting setting
or using @) that is 100% bug-free and working as intended. So no, there's
nothing strange about it if you buy into that approach. If you don't (and
I know you don't) - that's absolutely fine - it's up to you.Zeev
I just wanted to bring up a few other points. First, as I think Stanislav
has done a good job of pointing out, the flexibility of PHP is one of its
greatest features. The nice thing about a flexible and forgiving language
is that you can always put additional things in place on top of it to make
it more strict and rigid if you want. Once you force a language to be
strict and rigid, however, it's much harder, if not impossible, to add back
in flexibility.A lot of my emails on this thread have been focused on the burden to
developers caused by the BC break. While I still think that is an important
consideration, it distracted me from my initial view which was we shouldn't
do this because it's just a bad idea. I understand all of the arguments for
enforcing variable initialization. I agree with most of them as well.
However, I think there are a myriad of ways that individuals and teams can
do that enforcement without forcing it on every single developer whether
they want it or not.A lot of comparisons have been made to other languages. I do a lot of work
with javascript and I have a good amount of experience with c# as well.
I've used many other languages at times (c, c++, java, perl, ruby, etc.) as
well. In c#, you don't have to initialize your variables - you have to
declare them. Some types, like ints, are automatically initialized to 0
unless explicitly initialized to something else. PHP doesn't require you to
declare variables. So, while c# might require "int i; i++;" you can achieve
the same thing in PHP with "$i++;" - neither one requires an explicit
initialization.A few people have referred to the fact that I have instances of undeclared
variables as technical debt. As I said earlier, I've engaged in these
discussions because I don't think just calling something technical debt
should be justification for a change. The fact that a large number of
developers might have technical debt in a certain area should be considered
when weighing the pros and cons of a breaking change. That being said, I do
NOT consider such code to be technical debt or bad code that needs to be
fixed. The only way it becomes either of those if with the implementation
of this RFC. It's a bit disingenuous to tell developers they have to make
large changes, and when they push back, tell them it's their fault for
accruing so much technical debt - when it's the RFC itself that actually
causes the technical debt to begin with! *I will no longer engage in
conversations on this topic that relate to how you think my company should
conduct business or prioritize development. *Finally, since people seem hell bent on turning PHP into a language that
operates like all the others, instead of letting it keep its unique
qualities that make it great and different, I asked a c# developer I know
about how Microsoft deals with breaking changes. Here was his response:
"I’ve never heard of a breaking change when new versions of C# are
released. There are occasionally breaking changes when upgrading to a new
version of .NET, but they always (as far as I’m aware) have a way to
prevent the change from breaking anything by adding a parameter the app’s
configuration."--
Chase Peeler
chasepeeler@gmail.com
Le 29 août 2019 à 18:13, Matthew Brown matthewmatthew@gmail.com a écrit :
I don’t think it’s helpful to compare C#’s BC policies to PHP’s. C# is used today mostly as its architect intended at its founding. PHP, having transitioned from a templating system to a fully-fledged language, is used quite differently.
Today, PHP is a fully-fledged language and a templating system.
—Claude
Before reading the responses to this thread, I had honestly never
encountered a PHP developer who thought using uninitialized variables
was fine. I knew it worked, but I always considered this to basically be
the PHP equivalent of undefined behavior in C. And I don't think anyone
would get mad if a new GCC version broke the way they were abusing UB.
To me and to every developer I've ever known, the only difference
between a notice and a warning is the severity of the error. But they're
both considered errors - mistakes you made in your code that you need to
fix. I'm fairly certain this is how most developers treat them in the
real world.
Either way, if you want a less strict language, that language already
exists: It's the current version of PHP and you and everyone else who
likes the way it works can keep using it.
Meanwhile, I think most people currently doing serious PHP work would
love some more strictness and I don't think keeping your old code
running on a brand new version of the language is a good enough reason
to keep this feature out of 8.0. What's the point of even having major
releases if every potential BC break gets shot down by the same 3 people
on this mailing list?
As for the check engine light analogy, I guess instead of saying "this
is fine", you just smash your entire dashboard with a hammer to make the
problem go away. Because that's what using @ or error_reporting does.
I hope this RFC passes, but I don't see any point in discussing it
further here, so I'll go back to lurking now.
On Thu, Aug 29, 2019 at 4:02 PM Aegir Leet via internals
<internals@lists.php.net mailto:internals@lists.php.net> wrote:I know what the manual says about notices. But I don't agree with interpreting "could happen in the normal course of running a script" as "it's perfectly fine if this part of your code triggers a notice consistently and every time it goes down this particular code path". Rather, I've always interpreted this as "under certain, rare, unforeseen circumstances, your code could generate a notice here, probably because of something that is outside of your control". That's how I've always treated them at least.
And that's entirely within your right to do so - but what the manual
says is accurate. Calling me delusional in my interpretation of it is
somewhat awkward (to put it mildly), I have a pretty good idea of why
we added the different error levels - I wrote much of it myself.The whole point of having notices as something that's separate from
warnings is that they have different semantics, and that semantics is
captured very accurately in the manual. They are used to mark issues
which may be problems, but may also be perfectly fine (unlike
warnings, which generally speaking mean that something bad happened,
but not bad enough to halt execution). Notices were meant to help you
implement a more strict style of coding, and they may help you catch
certain types of bugs, but you can have perfectly working, bug-free
code that generates notices.Regardless of the exact semantics, don't you think a program that generates a constant stream of notices is a bit strange? That sounds like something everyone would naturally want to avoid. You don't drive your car with the check engine light permanently on and say "this is fine", right?
Except you can purposely turn off this 'check engine' light, never to
see it again if you choose to. And that it's really not at all
similar to 'check engine', but a lot closer to 'check cleaning fluid',
or even 'clean windshield' (if cars had a dashboard light for that).
Even that is not a good analogy - as folks often actually purposely
write code that generates notices (which would be purposely hidden,
either by error_reporting setting or using @) that is 100% bug-free
and working as intended. So no, there's nothing strange about it if
you buy into that approach. If you don't (and I know you don't) -
that's absolutely fine - it's up to you.Zeev
From: Aegir Leet aegir@aegir.sexy
Either way, if you want a less strict language, that language already
exists: It's the current version of PHP and you and everyone else who
likes the way it works can keep using it.
For approximately 3 years. Please remember "end of life". We'd still be using php5 today if it weren't for "end of life". I interpret the above paragraph as a request to split between p++ and php classic. I'd be fine with that and use php classic, but I believe the idea of splitting failed by a very wide margin.
- Todd
Le 29 août 2019 à 18:25, Aegir Leet aegir@aegir.sexy a écrit :
Either way, if you want a less strict language, that language already
exists: It's the current version of PHP and you and everyone else who
likes the way it works can keep using it.
Meanwhile, I think most people currently doing serious PHP work would
love some more strictness and I don't think keeping your old code
running on a brand new version of the language is a good enough reason
to keep this feature out of 8.0.
Strictness is undoubtedly a good thing — as a tool, not as a dogma. But BC break is not necessary for more strictness. As of today, you can write a custom error-handler that converts all non-handled warnings into program crashes (after having sent a fiery bug report to the developer).
—Claude
Am 29.08.2019 um 18:25 schrieb Aegir Leet aegir@aegir.sexy:
Before reading the responses to this thread, I had honestly never
encountered a PHP developer who thought using uninitialized variables
was fine.
Now you have. Nice to meet you.
I knew it worked, but I always considered this to basically be
the PHP equivalent of undefined behavior in C. And I don't think anyone
would get mad if a new GCC version broke the way they were abusing UB.
That's where you are mixing things up: It is well-defined behaviour, even if you personally don't like it.
A better analogy is static variables in C. It is common (and not considered bad) practice to not explicitly set a variable to 0 as that is the default value.
Example: https://github.com/git/git/blob/6d5b26420848ec3bc7eae46a7ffa54f20276249d/delta-islands.c#L26
- Chris
Hi!
encountered a PHP developer who thought using uninitialized variables
was fine.Now you have. Nice to meet you.
And there are more of us. You learn something new every day!
I knew it worked, but I always considered this to basically be
the PHP equivalent of undefined behavior in C. And I don't think anyone
It's not. It's very well defined behavior, that is not going to break -
unless it is broken intentionally in a zeal for adding more strictness
for the sake of strictness. So, another thing to learn. I love learning
new things, and love helping others do so!
--
Stas Malyshev
smalyshev@gmail.com
On Thu, Aug 29, 2019 at 2:29 PM Stanislav Malyshev smalyshev@gmail.com
wrote:
I knew it worked, but I always considered this to basically be
the PHP equivalent of undefined behavior in C. And I don't think anyoneIt's not. It's very well defined behavior, that is not going to break -
unless it is broken intentionally in a zeal for adding more strictness
for the sake of strictness. So, another thing to learn. I love learning
new things, and love helping others do so!It is well defined. It's also, in my PERSONAL opinion, gross AF. That
doesn't make me right or better or anything other than opinionated.
Other opinions:
- I'd quite like PHP to be a little less gross in places like this.
- I think Nikita's hitlist here is a step in the right direction, however...
- I DON'T think the cost to BC is justified in all cases. For example, an
exception for read of undefined vars is traumatic BC. - I think declare(strict_types=1); already solved a very similar problem
and could easily be applied to future issue like this.
So how about we suck it up, put on our big girl panties, and just embrace
declares (including namespace scoped declares and/or a modern version of
.htaccess)
-Sara
On Thu, Aug 29, 2019 at 2:29 PM Stanislav Malyshev smalyshev@gmail.com
wrote:I knew it worked, but I always considered this to basically be
the PHP equivalent of undefined behavior in C. And I don't think
anyoneIt's not. It's very well defined behavior, that is not going to break -
unless it is broken intentionally in a zeal for adding more strictness
for the sake of strictness. So, another thing to learn. I love learning
new things, and love helping others do so!It is well defined. It's also, in my PERSONAL opinion, gross AF. That
doesn't make me right or better or anything other than opinionated.Other opinions:
- I'd quite like PHP to be a little less gross in places like this.
- I think Nikita's hitlist here is a step in the right direction,
however...- I DON'T think the cost to BC is justified in all cases. For example, an
exception for read of undefined vars is traumatic BC.- I think declare(strict_types=1); already solved a very similar problem
and could easily be applied to future issue like this.So how about we suck it up, put on our big girl panties, and just embrace
declares (including namespace scoped declares and/or a modern version of
.htaccess)-Sara
Hi Sara,
I do agree with most of it, especially about the big girl panties part, but
I do disagree with the declares part.
There should be one general use declare I think - declare(strict=1) - and
it should be the mode where PHP is going as a language into the future
and contain the strict types, stricter operators, the full suite of error
level rework (include everything Nikita has added in this RFC and probably
work on next iteration later),
have other stuff cleaned up too?
Here's the rationale:
Projects these days tend to be sizeable and growing all the time - they
require strictness to be maintainable by multiple people. We have seen a
rise of more strict and less feature-rich languages that are becoming a day
to day instruments for many things (Go anyone?) and the average skill of
the workforce has gone down somewhat a lot these past 10-15 years. So
tightening the screws is somewhat a necessity these days and leaving PHP
with its idiosyncrasies as it is right now in the weak mode is not a good
idea for the future. People have changed, development has changed, tools
have changed, how we write PHP code has changed DRAMATICALLY and PHP
community has been keeping up with past 5 years of PHP development faster
than PHP is evolving itself. I mean take NodeJS and JavaScript - their dev
cycles are running at breakneck speeds and you basically have to re-learn
things on a yearly basis to stay up to date. But it is a mess because the
ecosystem is young.
In PHP our ecosystem is mature, we have very good libraries and frameworks
that have clear release cycles and have reasonable upgrade paths and do
keep up with PHP itself - the adoption rates are probably at their highest
right now.
I say it's time to capitalize on this momentum and settle into a rhythm of
improving the language and its ecosystem by streamlining and building for
the next 20 years of it's lifecycle. With JIT coming up, a lot of things
will start to become possible and there are going to be a lot of things
that you want to make more explicit in the code to make sure JIT can take
advantage of and optimise.
So, back to the strict mode idea: why not introduce that mode in PHP 8
(fold strict_types into it and have a depreciation notice for strict_types
so people switch to declare(strict_mode=1) ), continue developing stuff for
that strict mode during the life of 8 versions and state everywhere that
this is preferred and future proof mode, in PHP 9 starts deprecating things
in non-strict mode pushing people to fix things like undefined variables,
index access notices, have more strict operators. An in PHP 10 basically
sunset the bad parts of the non-strict mode getting it closer up to the
stricter version in terms of the WTF parts of the language, but still leave
the fully dynamic and strict modes. Provided, ofc, that it is feasible,
though I would completely sunset non-strict mode at that point and leave
only one mode.
This essentially gives about a 10-year timeline of messaging, depreciation
and warnings to everyone. And at that point, if someone still did not do
anything to fix up things - well, I'm sorry, but it's your problem then to
figure out. I have done a few major 5 to 7 upgrades, one of them was an
especially bad case of PHP 5.1 to 7.1 cause it relied on PHP 4 behaviours
that were deprecated with PHP 5.0 and 5.1 and fatal error in 7 - it is not
as bad as many people think.
Hi,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.
As a user dealing with a big legacy code-base that's still being in heavy
use and active development, while I appreciate this RFC in general, let me
please voice my concerns about promoting "Undefined index: %s" from
E_NOTICE
to E_WARNING
without also doing other changes.
The point is that in many cases, PHP still tends to just emit an E_WARNING
for otherwise pretty exceptional cases, like being unable to open a file,
or failing network operations. Now normally, you will of course check
return values, but if you mess it up, the risk of bad things happening is
too big, so right now, it's sensible to treat E_WARNING
as fatal in
production.
E_NOTICEs on the other hand are extremely uncritical (minus the undefined
variable case you've highlighted), so it's sensible to ignore those in
production and it's tempting to do so even in development and, I freely
admit, that's totally the case in the code-base I'm dealing with and I
would assume others would also have it configured that way. Code designed
to avoid "Undefined index: %s" is very boilerplaty to write and in various
code-bases (including ours), accessing undefined indexes in arrays is
mostly inconsequential.
So this leaves me (and I assume others) in kind of a pickle, because it
feels that right now it's still too risky to not treat E_WARNING
as fatal
in production and on the other hand, this RFC is going to turn completely
harmless undefined index access into an E_WARNING.
Even if you don't care about my particular code-base (which I would totally
understand), please consider that this is quite the BC breakage in general
and in our case, it will probably force us to run with a patched PHP engine
as we are unable to clean the code up in any kind of reasonable time frame.
Again - that's my problem. I know. But I still would like to voice this
concern.
Of course, even when passing this RFC in full, there are options you could
provide for people in our kind of situation:
- If all functions that currently emit an
E_WARNING
in cases where they
should actually throw could be made to throw, then it would be safe to run
production without treatingE_WARNING
as fatal. I'm afraid that too is a
big BC break, but at least it's breaking code running into otherwise
serious issues rather than code doing something mostly benign. - If this can't be done, which I totally understand, then please consider a
way for a error handler to distinguish between various errors, notices and
warnings without having to string match on error messages. That feels
incredibly brittle and also ties the PHP language into ossified error
messages that can never be changed without also causing potential BC issues.
Still. I wholeheartedly thank you all for your recent efforts to clean up
the language and bring it forward to the current state of things. But
please consider the huge swaths of existing code which sometimes cannot be
practically changed.
I do not have any kind of voting rights, so in the end my opinion doesn't
matter, but if I had the ability to vote, I would have to vote "no" over
this unless some kind of escape hatch is provided.
Thank you
Philip
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...
Nikita,
Thank you for your effort in putting together this RFC and explaining
the rationale for each change. From my perspective, converting more
error conditions from a notice/warning to an exception as proposed
will be a welcome step forward for the language.
I've frequently used PHP to write one-time scripts for migrating data
between services, or scripting changes to thousands of items via an
API. The lack of exceptions for things like undefined variables and
using a scalar value as an array has bitten me on multiple occasions.
There have even been times when simple mistakes like a typo in a
variable name have led to data loss, since instead of causing the
script to halt it just output a notice and continued running with
bad data.
In my experience, PHP's historical lax treatment of errors, far from
making it faster and easier to write scripts, actually makes it take
longer since I have to add extra assertions and boilerplate custom
error handling code in order to ensure that scripts don't keep
running in a broken state when one of these errors occurs.
So in summary, I think the proposed RFC is a solid step forward which
will help prevent expensive mistakes and make it simpler to write
robust code.
With appreciation,
Theodore
Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...https://wiki.php.net/rfc/engine_warnings
Regards,
Nikita
Heads up: This RFC may go to vote tomorrow.
Nikita
Den 2019-09-10 kl. 15:31, skrev Nikita Popov:
Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...https://wiki.php.net/rfc/engine_warnings
Regards,
NikitaHeads up: This RFC may go to vote tomorrow.
Nikita
Hi,
I recall an issue brought up about treatment of logfiles in production
environment
where PHP warning messages show up.
Now, this RFC reclassifies some notices to warnings and some warnings to
errors.
Now suppose one have as a strategy to correct warnings & errors in
logfiles, given
that this RFC will lead to new items showing up in logfiles.
Is it then worth mentioning in the RFC how this will affect handling to
correct
warnings & errors in logfiles? E.g. face the changes and fix it or
write some
clever error handler to manage it or just try to suppress the new items.
Anyway, I'm in favour of this RFC since it gives a more consistent
classification
of notices, warnings & errors.
r//Björn L
Le 10 sept. 2019 à 15:31, Nikita Popov nikita.ppv@gmail.com a écrit :
Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...https://wiki.php.net/rfc/engine_warnings
Regards,
NikitaHeads up: This RFC may go to vote tomorrow.
Nikita
I have objections to those two reclassifications:
- Undefined offset: %d — Notice → Warning
- Undefined index: %d — Notice → Warning
From experience, having to dutifully initialise each and every key in an array is burdensome. I understand the rationale of enforcing that in some coding standard; but whether those particular missing index should be considered as unexpected (therefore deserving a Warning) is mostly a question of coding style.
This is in principle a similar issue as using uninitialised variables, which, as noted in this thread, is a perfectly accepted coding pattern in some languages (the issue being distinct from undeclared variables). I say “in principle”, because a perfectly reasonable coding style may choose to enforce initialisation of variables, but not of array keys.
PHP has the advantage of supporting various coding styles. We should give the opportunity to the users to say declaratively (and precisely) what, in their coding style, is considered as acceptable, e.g.
declare(
uninitialized_variables: error
uninitilalized_index: none
);
of course, possibly at a package-level declare. That would, for example, enable people to place legacy code in lax mode and chose a stricter mode for new code, even letting the precise notion of strictness vary with fashion without having to review working code written two years ago.
That said, as long as those issues are handled as errors (as in: set_error_handler()
) rather than exceptions, one may write a proper error handler that does the distinction (I do that). However, an error handler has the disadvantage of being global, making difficult the integration of code written with differing coding standards.
—Claude
Le 10 sept. 2019 à 15:31, Nikita Popov nikita.ppv@gmail.com a écrit :
Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...https://wiki.php.net/rfc/engine_warnings
Regards,
NikitaHeads up: This RFC may go to vote tomorrow.
Nikita
I have objections to those two reclassifications:
- Undefined offset: %d — Notice → Warning
- Undefined index: %d — Notice → Warning
From experience, having to dutifully initialise each and every key in an array is burdensome. I understand the rationale of enforcing that in some coding standard; but whether those particular missing index should be considered as unexpected (therefore deserving a Warning) is mostly a question of coding style.
This is in principle a similar issue as using uninitialised variables, which, as noted in this thread, is a perfectly accepted coding pattern in some languages (the issue being distinct from undeclared variables). I say “in principle”, because a perfectly reasonable coding style may choose to enforce initialisation of variables, but not of array keys.
PHP has the advantage of supporting various coding styles. We should give the opportunity to the users to say declaratively (and precisely) what, in their coding style, is considered as acceptable, e.g.
declare(
uninitialized_variables: error
uninitilalized_index: none
);of course, possibly at a package-level declare. That would, for example, enable people to place legacy code in lax mode and chose a stricter mode for new code, even letting the precise notion of strictness vary with fashion without having to review working code written two years ago.
That said, as long as those issues are handled as errors (as in:
set_error_handler()
) rather than exceptions, one may write a proper error handler that does the distinction (I do that). However, an error handler has the disadvantage of being global, making difficult the integration of code written with differing coding standards.—Claude
--
I’ve seen a number of people that have concerns about PHP throwing actual errors (as opposed to notices) because they try to use a variable/offset that doesn’t exist, and of course there is often a proposal to have a declare statement or something similar, to allow their “code style” to run without errors.
So, my proposal to the situation is to introduce a single declare that solves that problem, once and for all.
declare(sloppy=1);
This would suppress any errors about undefined variables, array offsets, would reverse the “bare words" change when encountering an undefined constant, etc. Heck, for good measure this mode could even re-implement register_globals and magic_quotes, because why not?
If you want to write sloppy code, that is entirely your prerogative, but please just own it for what it is, and stop pretending that it’s some herculean task to either define variables/offsets first; or check if they’re defined; or use an appropriate method to access them that specifically allows for undefined variables/offsets (i.e. the ?? and ??= operators)
declare(sloppy=1);
I like this idea. Strict by default, sloppy by (code-level) config.
Le 12 sept. 2019 à 10:17, Stephen Reay php-lists@koalephant.com a écrit :
I’ve seen a number of people that have concerns about PHP throwing actual errors (as opposed to notices) because they try to use a variable/offset that doesn’t exist, and of course there is often a proposal to have a declare statement or something similar, to allow their “code style” to run without errors.
So, my proposal to the situation is to introduce a single declare that solves that problem, once and for all.
declare(sloppy=1);
This would suppress any errors about undefined variables, array offsets, would reverse the “bare words" change when encountering an undefined constant, etc. Heck, for good measure this mode could even re-implement register_globals and magic_quotes, because why not?
If you want to write sloppy code, that is entirely your prerogative, but please just own it for what it is, and stop pretending that it’s some herculean task to either define variables/offsets first; or check if they’re defined; or use an appropriate method to access them that specifically allows for undefined variables/offsets (i.e. the ?? and ??= operators)
Declare(sloppy=yeah) is not granular enough. To all: please, do understand that everything is not black or white; this remark is not directed specifically to that particular issue, this is an attitude I see regularly on that mailing list.
There is no such thing as “one true strict coding standard” and “one legacy lax coding standard”. For instance:
-
As time passes, we learn by experience what features were plain blunders (magic_quotes?), what features should have been more strict for the sake of catching bugs without imposing too much burden on users, what features could have been more strict, although that would impose to write lot of boiler code, etc. This process does not belong exclusively to some past dark age of sloppy and unsecure coding practices.
-
The degree of wanted strictness vary depending on occasions. For example when I’m writing a throw-away script, some notices are okay to indicate possible problems, but I’m not going to write boilerplate code (or, worse, put a @ in front of everything) just for the sake of silencing them. (But I certainly do not want stupid things like mistyped constants converted to string literals.) On the other hand, when I’m writing a critical part of an application, I am careful to write down everything precisely, and having to write explicitly and once for all that, yes, this precise variable must have that default value, is a minimal part of the time passed to write, re-read and review the code.
—Claude
For example when I’m writing a throw-away script, some notices are okay to
indicate possible problems
Maybe it's just me, but even in throw-away scripts, I've lost much more
time because of warnings/notices going unnoticed, than I've saved thanks to
PHP's forgiving nature.
Hence even in the shittiest of my scripts, I usually end up registering an
error handler to throw an exception even for the smallest notice. At least,
I always get an exception right in my face when something's unexpected, so
I can fix it and move on, and avoid surprises later on.
Sure, in a quick script, I do see some value in being able to write stuff
like:
@ $array['non_existing_key']++;
It's still sloppy though: what you're really doing is muting a notice and
incrementing null.
Instead, I feel like there should be a stronger support from the language
to specifically handle this kind of use cases, rather than using them as a
justification for not *severely *hardening error reporting.
I don't think there are that many such *potentially *legitimate use cases,
so maybe we could just list the use cases and think about a more elegant
solution to solve them?
In other words, if that was only me, the whole notice/warning stuff would
go, and PHP would only have exceptions.
Undefined variables would throw, undefined array keys would throw, and use
cases like the above would have stronger language support to avoid
boilerplate code full of if(isset()).
— Benjamin
Le 12 sept. 2019 à 10:17, Stephen Reay php-lists@koalephant.com a
écrit :I’ve seen a number of people that have concerns about PHP throwing
actual errors (as opposed to notices) because they try to use a
variable/offset that doesn’t exist, and of course there is often a proposal
to have a declare statement or something similar, to allow their “code
style” to run without errors.So, my proposal to the situation is to introduce a single declare that
solves that problem, once and for all.declare(sloppy=1);
This would suppress any errors about undefined variables, array offsets,
would reverse the “bare words" change when encountering an undefined
constant, etc. Heck, for good measure this mode could even re-implement
register_globals and magic_quotes, because why not?If you want to write sloppy code, that is entirely your prerogative, but
please just own it for what it is, and stop pretending that it’s some
herculean task to either define variables/offsets first; or check if
they’re defined; or use an appropriate method to access them that
specifically allows for undefined variables/offsets (i.e. the ?? and ??=
operators)Declare(sloppy=yeah) is not granular enough. To all: please, do understand
that everything is not black or white; this remark is not directed
specifically to that particular issue, this is an attitude I see regularly
on that mailing list.There is no such thing as “one true strict coding standard” and “one
legacy lax coding standard”. For instance:
As time passes, we learn by experience what features were plain blunders
(magic_quotes?), what features should have been more strict for the sake of
catching bugs without imposing too much burden on users, what features
could have been more strict, although that would impose to write lot of
boiler code, etc. This process does not belong exclusively to some past
dark age of sloppy and unsecure coding practices.The degree of wanted strictness vary depending on occasions. For example
when I’m writing a throw-away script, some notices are okay to indicate
possible problems, but I’m not going to write boilerplate code (or, worse,
put a @ in front of everything) just for the sake of silencing them. (But I
certainly do not want stupid things like mistyped constants converted to
string literals.) On the other hand, when I’m writing a critical part of an
application, I am careful to write down everything precisely, and having to
write explicitly and once for all that, yes, this precise variable must
have that default value, is a minimal part of the time passed to write,
re-read and review the code.—Claude
чт, 12 сент. 2019 г. в 12:32, Benjamin Morel benjamin.morel@gmail.com:
For example when I’m writing a throw-away script, some notices are okay
to
indicate possible problemsMaybe it's just me, but even in throw-away scripts, I've lost much more
time because of warnings/notices going unnoticed, than I've saved thanks to
PHP's forgiving nature.
Hence even in the shittiest of my scripts, I usually end up registering an
error handler to throw an exception even for the smallest notice. At least,
I always get an exception right in my face when something's unexpected, so
I can fix it and move on, and avoid surprises later on.Sure, in a quick script, I do see some value in being able to write stuff
like:@ $array['non_existing_key']++;
It's still sloppy though: what you're really doing is muting a notice and
incrementing null.
Instead, I feel like there should be a stronger support from the language
to specifically handle this kind of use cases, rather than using them as a
justification for not *severely *hardening error reporting.
I don't think there are that many such *potentially *legitimate use cases,
so maybe we could just list the use cases and think about a more elegant
solution to solve them?In other words, if that was only me, the whole notice/warning stuff would
go, and PHP would only have exceptions.
Undefined variables would throw, undefined array keys would throw, and use
cases like the above would have stronger language support to avoid
boilerplate code full of if(isset()).— Benjamin
Every single workplace I worked in past 5 years always had 0 tolerance
policy for all notices, warnings and E_STRICT.
Since I started PHP in 2005, I have always worked with a 0
warning/notice/strict tolerance policy, in every workplace I have ever
worked. All those were fixed as bugs, heck even management pointed out
those from logging aggregation and made bugs to be fixed.
At this point, if I see that the company does not do this, I skip it.
Usually, it is a sign of way more stuff being wrong, but this alone is
already enough to have reservations about the advertised position.
The world has moved on how software is developed since the early 2000's
when this was okay. These days, at least in my dev circle, it is not okay
to have notices/warnings in your code.
On Thu, 12 Sep 2019 at 12:32, Arvids Godjuks arvids.godjuks@gmail.com
wrote:
Every single workplace I worked in past 5 years always had 0 tolerance
policy for all notices, warnings and E_STRICT.
Well, that's fine then, you don't need this change. It will make zero
difference to you whether something is classified as Notice or Warning.
Regards,
Rowan Tommins
[IMSoP]
On Thu, 12 Sep 2019 at 11:32, Benjamin Morel benjamin.morel@gmail.com
wrote:
I don't think there are that many such *potentially *legitimate use cases,
so maybe we could just list the use cases and think about a more elegant
solution to solve them?
Yes, please. If we can focus less on vague anecdotes and opinions on both
sides, we can look at making the language more pleasant to use.
For instance, for undefined array keys, what if we had an operator for
"initialise and retrieve", such as $foo[? 'bar']. Then we could simplify
ugly code like this:
if ( ! isset($foo[$key1]) {
$foo[$key1] = [];
}
if ( ! isset($foo[$key1][$key2]) {
$foo[$key1][$key2] = 0;
}
$foo[$key1][$key2]++;
With something safe but succinct like this:
$foo[? $key1][? $key2]++;
Unlike the error suppression @ operator, this is not saying "I know I'm
doing something wrong, do it anyway"; it's saying "I want to do this
specific thing, I just want to do it in fewer lines of code".
The more helpers like this we have, the more I'd be amenable to
eventually raising things to Error - although I still think that should
be done over a longer period of time than a single release cycle.
Regards,
Rowan Tommins
[IMSoP]
Hey Rowan,
http://ocramius.github.com/
On Thu, Sep 12, 2019 at 3:30 PM Rowan Tommins rowan.collins@gmail.com
wrote:
For instance, for undefined array keys, what if we had an operator for
"initialise and retrieve", such as $foo[? 'bar']. Then we could simplify
ugly code like this:if ( ! isset($foo[$key1]) {
$foo[$key1] = [];
}
if ( ! isset($foo[$key1][$key2]) {
$foo[$key1][$key2] = 0;
}
$foo[$key1][$key2]++;With something safe but succinct like this:
$foo[? $key1][? $key2]++;
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
Marco Pivetta
Le 12 sept. 2019 à 15:33, Marco Pivetta ocramius@gmail.com a écrit :
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
Marco Pivetta
That violates blatantly DRY (twice the exact same lengthy expression $foo[$key1][$key2]
), so it is not a satisfactory solution.
—Claude
Le 12 sept. 2019 à 15:33, Marco Pivetta ocramius@gmail.com a écrit :
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
Marco Pivetta
That violates blatantly DRY (twice the exact same lengthy expression
$foo[$key1][$key2]
), so it is not a satisfactory solution.And that's why PHP is so awesome. You don't have to do all these stupid
tricks just to do something simple like increment a counter. But, it looks
like we're going to throw that out of the window because some people think
that since they like doing it like the way above, everyone should have to.
—Claude
--
Chase Peeler
chasepeeler@gmail.com
чт, 12 сент. 2019 г. в 16:02, Chase Peeler chasepeeler@gmail.com:
On Thu, Sep 12, 2019 at 9:55 AM Claude Pache claude.pache@gmail.com
wrote:Le 12 sept. 2019 à 15:33, Marco Pivetta ocramius@gmail.com a écrit :
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
Marco Pivetta
That violates blatantly DRY (twice the exact same lengthy expression
$foo[$key1][$key2]
), so it is not a satisfactory solution.And that's why PHP is so awesome. You don't have to do all these stupid
tricks just to do something simple like increment a counter. But, it looks
like we're going to throw that out of the window because some people think
that since they like doing it like the way above, everyone should have to.—Claude
--
Chase Peeler
chasepeeler@gmail.com
Easy, because experience shows that leads to bugs and lots of them.
Security issues even.
If you want to write predictable code - you have to init your
variables/arrays. And check for existence/null. If fixed at least a few
dozen bugs in my system I took over in the last few months specifically
because of undefined variables or indexes.
It works for small stuff, but when you have a codebase with 100+k LOC and
more, you have to go strict or it starts to cost a lot of money and
personnel to keep things running along.
--
Arvīds Godjuks
+371 26 851 664
arvids.godjuks@gmail.com
Skype: psihius
Telegram: @psihius https://t.me/psihius
On Thu, Sep 12, 2019 at 10:06 AM Arvids Godjuks arvids.godjuks@gmail.com
wrote:
чт, 12 сент. 2019 г. в 16:02, Chase Peeler chasepeeler@gmail.com:
On Thu, Sep 12, 2019 at 9:55 AM Claude Pache claude.pache@gmail.com
wrote:Le 12 sept. 2019 à 15:33, Marco Pivetta ocramius@gmail.com a écrit
:$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
Marco Pivetta
That violates blatantly DRY (twice the exact same lengthy expression
$foo[$key1][$key2]
), so it is not a satisfactory solution.And that's why PHP is so awesome. You don't have to do all these stupid
tricks just to do something simple like increment a counter. But, it looks
like we're going to throw that out of the window because some people think
that since they like doing it like the way above, everyone should have to.—Claude
--
Chase Peeler
chasepeeler@gmail.comEasy, because experience shows that leads to bugs and lots of them.
Security issues even.
If you want to write predictable code - you have to init your
variables/arrays. And check for existence/null. If fixed at least a few
dozen bugs in my system I took over in the last few months specifically
because of undefined variables or indexes.Never once have I advocated not initializing variables or arrays. I'm just
saying that we shouldn't force such behavior. Many of us can figure out
when we need the extra boilerplate and when we don't. Don't force us to
have to deal with the additional burden in every single case because
someone else can't.
It works for small stuff, but when you have a codebase with 100+k LOC and
more, you have to go strict or it starts to cost a lot of money and
personnel to keep things running along.--
Arvīds Godjuks+371 26 851 664
arvids.godjuks@gmail.com
Skype: psihius
Telegram: @psihius https://t.me/psihius
--
Chase Peeler
chasepeeler@gmail.com
Le 12 sept. 2019 à 15:33, Marco Pivetta ocramius@gmail.com a écrit :
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
Marco Pivetta
That violates blatantly DRY (twice the exact same lengthy expression
$foo[$key1][$key2]
), so it is not a satisfactory solution.
Agreed; it's certainly neater than all the isset() checks, but it's
definitely a bit ugly.
To clarify my point, the reason why people write this:
$foo[$key1][$key2]++;
Is not because they're lazy, it's because it expresses their intent.
The ?key syntax was one suggestion for how to express the intent safely in
that particular scenario. Another way might be that the array is
initialised a different way; completely off the top of my head, something
like this:
$foo = new Dictionary<string, Dictionary<string, int=0>>;
That could express the intent of "this variable is going to be used as an
accumulator with these dimensions".
The "if isset" lines, in my opinion, don't express any intent, and they
don't protect against any real errors; they're just noise to work around a
short-coming in the language.
Regards,
Rowan Tommins
[IMSoP]
On Thu, Sep 12, 2019 at 4:11 PM Rowan Tommins rowan.collins@gmail.com
wrote:
Le 12 sept. 2019 à 15:33, Marco Pivetta ocramius@gmail.com a écrit :
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
Marco Pivetta
That violates blatantly DRY (twice the exact same lengthy expression
$foo[$key1][$key2]
), so it is not a satisfactory solution.Agreed; it's certainly neater than all the isset() checks, but it's
definitely a bit ugly.To clarify my point, the reason why people write this:
$foo[$key1][$key2]++;
Is not because they're lazy, it's because it expresses their intent.
The ?key syntax was one suggestion for how to express the intent safely in
that particular scenario. Another way might be that the array is
initialised a different way; completely off the top of my head, something
like this:$foo = new Dictionary<string, Dictionary<string, int=0>>;
That could express the intent of "this variable is going to be used as an
accumulator with these dimensions".The "if isset" lines, in my opinion, don't express any intent, and they
don't protect against any real errors; they're just noise to work around a
short-coming in the language.
FTR this is basically what Python does via defaultdict:
https://docs.python.org/3/library/collections.html#collections.defaultdict
I think it is the "cleanest" solution to this problem overall. Though it
does need a separate structure, rather than our favorite PHP array.
Nikita
FTR this is basically what Python does via defaultdict:
https://docs.python.org/3/library/collections.html#collections.defaultdict
Thanks, I'm glad I wasn't completely daft thinking there might be some
way to express it. :)
I think it is the "cleanest" solution to this problem overall. Though
it does need a separate structure, rather than our favorite PHP array.
Indeed it does, and I think that's the better route to making PHP a
stricter language: before we take away the existing features, add the
new ones that let you express things better.
PHP's array type, and its type system in general, allow a lot of very
expressive algorithms which are hard to do with more rigid type systems.
Modern languages like C# bring back that expressiveness using things
like generics, a rich library of built-in collections and interfaces,
and so on; they don't just say "sorry, you can't do that".
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]
Hi!
FTR this is basically what Python does via defaultdict:
https://docs.python.org/3/library/collections.html#collections.defaultdictI think it is the "cleanest" solution to this problem overall. Though it
does need a separate structure, rather than our favorite PHP array.
This is one of the most annoying quirks of python - that you have to use
special package to do simplest tasks like counting anything by key or
write annoying boilerplate code that reminds python that counting starts
with 0. Now strictness zealots want to bring that into PHP. If I was a
person to do that, I'd definitely write a long "python sadness" text and
that would feature there prominently, but I don't have time to do that
so I just note that now, that it is very sad that the annoying quirks of
python are brought into php apparently because more strict is always
better.
--
Stas Malyshev
smalyshev@gmail.com
On Thu, Sep 12, 2019 at 10:11 AM Rowan Tommins rowan.collins@gmail.com
wrote:
Le 12 sept. 2019 à 15:33, Marco Pivetta ocramius@gmail.com a écrit :
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
Marco Pivetta
That violates blatantly DRY (twice the exact same lengthy expression
$foo[$key1][$key2]
), so it is not a satisfactory solution.Agreed; it's certainly neater than all the isset() checks, but it's
definitely a bit ugly.To clarify my point, the reason why people write this:
$foo[$key1][$key2]++;
Is not because they're lazy, it's because it expresses their intent.
The ?key syntax was one suggestion for how to express the intent safely in
that particular scenario. Another way might be that the array is
initialised a different way; completely off the top of my head, something
like this:$foo = new Dictionary<string, Dictionary<string, int=0>>;
That could express the intent of "this variable is going to be used as an
accumulator with these dimensions".The "if isset" lines, in my opinion, don't express any intent, and they
don't protect against any real errors; they're just noise to work around a
short-coming in the language.But, if you're dealing with a counter, then, the intent is that you are
going to start counting at 0 and increase it. In that case, if the variable
hasn't be initialized, or, the array key doesn't exist, it makes sense to
assume it's 0.
If you need to do something else besides assuming it's 0 and counting from
there, then put in the extra code to check for that.
I can do this already:
if(!isset($i)){
return false;
}
$i++;
So, why should I start having to do
if(!isset($i)){
$i = 0;
}
$i++;
when
$i++;
works just fine.
Regards,
Rowan Tommins
[IMSoP]
--
Chase Peeler
chasepeeler@gmail.com
But, if you're dealing with a counter, then, the intent is that you are
going to start counting at 0 and increase it.
This is not that clear as you may think. Several questions may come to mind when you will see incrementation of non-existing variable/key. Is it a bug
and this should be initialized with a different value than 0? Maybe a mistake on copy&paste? Maybe a typo?
One additional line will make your code much more obvious and easier to read and understand:
$i ??= 0;
$i++;
Your code is not only for compiler/parser, but also for humans. Expressing your intentions clearly is important - the less ambiguity the better.
Regards,
Robert Korulczyk
On Thu, Sep 12, 2019 at 10:43 AM Robert Korulczyk robert@korulczyk.pl
wrote:
But, if you're dealing with a counter, then, the intent is that you are
going to start counting at 0 and increase it.This is not that clear as you may think. Several questions may come to
mind when you will see incrementation of non-existing variable/key. Is it a
bug
and this should be initialized with a different value than 0? Maybe a
mistake on copy&paste? Maybe a typo?One additional line will make your code much more obvious and easier to
read and understand:$i ??= 0;
$i++;
And I'm totally in favor of writing code that way. What I'm not in favor of
is breaking all of the existing code that doesn't do it that way and works
perfectly fine because some people want to FORCE everyone to write it that
way.
Your code is not only for compiler/parser, but also for humans. Expressing
your intentions clearly is important - the less ambiguity the better.Regards,
Robert Korulczyk
--
Chase Peeler
chasepeeler@gmail.com
One additional line will make your code much more obvious and easier to read and understand:
$i ??= 0;
$i++;
I don't find this code at all obvious:
foreach ( $something as $foo ) {
$i ??= 0;
$i++;
}
I mean, huh? What's that zero doing there, is it resetting the variable
every loop?
Now, in that simple case, you can and probably should initialise the
counter before the loop:
$i=0;
foreach ( $something as $foo ) {
$i++;
}
But that's not the example I gave earlier! The example I gave earlier
was a multi-dimensional array:
$foo = [];
foreach ( $something as $key1 ) {
foreach ( $somethingElse as $key2 ) {
$foo[$key1][$key2]++;
}
}
Even using ??= the initialise-everything-before-use version looks like this:
$foo = [];
foreach ( $something as $key1 ) {
foreach ( $somethingElse as $key2 ) {
$foo[$key1] ??= [];
$foo[$key1][$key2] ??= 0;
$foo[$key1][$key2]++;
}
}
Again, the values are confusing: the end result will never contain an
empty array at the first level, and will never contain a 0 at the second
level.
Those two lines aren't aiding the readability of that algorithm in any
way; I have to read past them to find the actual business of the loop,
which is counting something, using the ++ operator.
What's more, they're not preventing any bugs either! If I accidentally
reuse $foo from a previous loop, the extra lines won't reinitialise
anything for me; if I initialise it to empty, the two loops are
functionally identical.
So that's where I came up with two suggestions to actually add to the
language, rather than just taking away:
- a more granular way to express that this code is not actually
error-prone, combining the 3 lines back into one - or, a way to express the intent of the code more clearly, such as
declaring the shape of an array
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]
W dniu 12.09.2019 o 22:45, Rowan Tommins pisze:
One additional line will make your code much more obvious and easier to read and understand:
$i ??= 0;
$i++;I don't find this code at all obvious:
foreach ( $something as $foo ) {
$i ??= 0;
$i++;
}
That is because it does not make sense. You should initialize $i before loop, since it does not need a loop at all (and you probably don't need ??= here):
$i ??= 0;
foreach ( $something as $foo ) {
$i++;
}
Even using ??= the initialise-everything-before-use version looks like this:
$foo = [];
foreach ( $something as $key1 ) {
foreach ( $somethingElse as $key2 ) {
$foo[$key1] ??= [];
$foo[$key1][$key2] ??= 0;
$foo[$key1][$key2]++;
}
}
Actually you need only one additional line:
$foo = [];
foreach ( $something as $key1 ) {
foreach ( $somethingElse as $key2 ) {
$foo[$key1][$key2] ??= 0;
$foo[$key1][$key2]++;
}
}
Again, the values are confusing: the end result will never contain an empty array at the first level, and will never contain a 0 at the second level.
It does not look confusing. You have two lines, for two intents - start counting from zero and increment counter on every loop iteration. If one
additional line is to much for making your code less ambiguous and more bug-free, then I won't even try to change your mind.
Regards,
Robert Korulczyk
Actually you need only one additional line:
$foo = [];
foreach ( $something as $key1 ) {
foreach ( $somethingElse as $key2 ) {
$foo[$key1][$key2] ??= 0;
$foo[$key1][$key2]++;
}
}
Why? If "assume $key2 exists as a key and is an integer" is so bad that
PHP should halt my program, why should "assume $key1 exists and is an
array" be perfectly OK?
It does not look confusing. You have two lines, for two intents - start counting from zero and increment counter on every loop iteration.
There is no intent to start counting at zero; the counter will never be
lower than 1. If we really wanted to express the intent, we would have
to write something like this:
$foo[$key1] ??= [];
if ( ! isset($foo[$key1][$key2]) ) {
$foo[$key1][$key2] = 1;
}
else {
$foo[$key1][$key2]++;
}
If one additional line is to much for making your code less ambiguous and more bug-free, then I won't even try to change your mind.
Please can you show me a bug that adding this line has avoided? I don't
doubt that the same warning saves bugs in other scenarios, but in this
scenario, the logic is unambiguous, and any additions are just to
suppress unnecessary errors.
To reiterate, my motivation here is to discuss features that help write
these scenarios with less boilerplate, and separate them from other
scenarios where there's a real bug risk which should raise an error.
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]
Why? If "assume $key2 exists as a key and is an integer" is so bad that PHP should halt my program, why should "assume $key1 exists and is an array"
be perfectly OK?
Warning is triggered by reading non-existing key, not assigning value to it. In $foo[$key1][$key2] ??= 0
you never try to read non-existing key.
Please can you show me a bug that adding this line has avoided? I don't doubt that the same warning saves bugs in other scenarios, but in this
scenario, the logic is unambiguous, and any additions are just to suppress unnecessary errors.
Well, then let's say that it is "lesser evil" - one additional line is better than ignoring reading uninitialized values. And IMO it is not a
"problem" that would justify introducing special syntax for saving one line in such niche case.
Regards,
Robert Korulczyk
Why? If "assume $key2 exists as a key and is an integer" is so bad that PHP should halt my program, why should "assume $key1 exists and is an array"
be perfectly OK?
Warning is triggered by reading non-existing key, not assigning value to it. In$foo[$key1][$key2] ??= 0
you never try to read non-existing key.
$foo[$key1] has to be read to determine if it's already an array, and if it has the key $key2, in the same way that in $foo[$key1]++, $foo[$key1] has to be read to determine if it's already an integer and what it's value is.
If we're talking about being strict, we shouldn't limit ourselves to what happens to give a warning today, we should be consistent in our reasoning. So if the reasoning is that accessing uninitialised array keys is dangerous, I should not be able to mention $foo[$key1][$key2] if $foo[$key1] doesn't yet exist.
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]
$foo[$key1] has to be read to determine if it's already an array, and if it has the key $key2, in the same way that in $foo[$key1]++, $foo[$key1] has
to be read to determine if it's already an integer and what it's value is.
$foo[$key1] needs to be read only to obtain previous value, type is irrelevant (obviously you will get error if types does not allow for such
operation, but it has nothing to do with accessing uninitialized variables/keys). You can't increment $foo[$key1] without knowing current value of
$foo[$key1] - you need to read it first. But you don't need to know previous value (or its type) to overwrite it (it does not matter what is
$foo[$key1] value if you do $foo[$key1] = 1
- it works similar to $foo = 1
);
Regards,
Robert Korulczyk
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
That violates blatantly DRY (twice the exact same lengthy expression
$foo[$key1][$key2]
), so it is not a satisfactory solution.
$foo[$key1][$key2]??++ ?
More seriously, yes as Marco suggested, yes we can already do it, and as
Claude pointed out, yes that's verbose.
What I had in mind with language support is some kind of code-level (per
line or block) switch that would allow uninitialized array keys to behave
in a certain way, depending on the context : we actually have not one,
but two good examples of this above, provided that $key1 and $key2 do not
exist:
- with [], an unitialized key would be initialized with an empty array
(already does that) - with ++, an unitialized key would be initialized with 0
Without the proper code-level switch, we could safely have both cases above
throw an exception.
— Benjamin
чт, 12 сент. 2019 г. в 15:33, Marco Pivetta ocramius@gmail.com:
Hey Rowan,
http://ocramius.github.com/On Thu, Sep 12, 2019 at 3:30 PM Rowan Tommins rowan.collins@gmail.com
wrote:For instance, for undefined array keys, what if we had an operator for
"initialise and retrieve", such as $foo[? 'bar']. Then we could simplify
ugly code like this:if ( ! isset($foo[$key1]) {
$foo[$key1] = [];
}
if ( ! isset($foo[$key1][$key2]) {
$foo[$key1][$key2] = 0;
}
$foo[$key1][$key2]++;With something safe but succinct like this:
$foo[? $key1][? $key2]++;
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
Marco Pivetta
This message contains a healthy dose of sarcasm.
Hi Marko and Rowan :)
Me reviewing the PR with that code
*Clicks "Changes required"
[ Please rewrite this statement into easy readable format with an if ]
- Clicks send *
Think what you must, but 6 months when you come back to code like this you
have to stop, look at it hard and figure out what the hell actually happens
there.
Breaks reading flow.
One thing I like PHP for is a distinct lack of huge amounts of syntax
sugar.
Take Ruby - it's a hell to read the code. Even Vagrantfile has tons of
results about what syntax for arrays to use and things breaking because you
end up mixing stuff and you get at least 4 different answers to the same
question and it looks like all are correct. Confusing as hell :)
What I'm trying to say is some of us choose PHP for it's "there is one
syntax - use it". If people want syntax sugar - there are other languages
that fit that much better. Leave us, peasants, in our peasant non-syntax
sugar world alone :D
But many of us would also like the language engine to tighten up some of
its extremely relaxed parts that do not fit in modern development
environments and the lowest bar of the code quality rise a bit. Otherwise,
the gap between high-end development and newbies is going to be even bigger
than it is now.
I hire people, that's part of my job. One of the criteria is the approach
to errors/warning/notices. Imagine how that goes.
--
Arvīds Godjuks
+371 26 851 664
arvids.godjuks@gmail.com
Skype: psihius
Telegram: @psihius https://t.me/psihius
On Thu, Sep 12, 2019 at 10:02 AM Arvids Godjuks arvids.godjuks@gmail.com
wrote:
чт, 12 сент. 2019 г. в 15:33, Marco Pivetta ocramius@gmail.com:
Hey Rowan,
http://ocramius.github.com/On Thu, Sep 12, 2019 at 3:30 PM Rowan Tommins rowan.collins@gmail.com
wrote:For instance, for undefined array keys, what if we had an operator for
"initialise and retrieve", such as $foo[? 'bar']. Then we could
simplify
ugly code like this:if ( ! isset($foo[$key1]) {
$foo[$key1] = [];
}
if ( ! isset($foo[$key1][$key2]) {
$foo[$key1][$key2] = 0;
}
$foo[$key1][$key2]++;With something safe but succinct like this:
$foo[? $key1][? $key2]++;
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
Marco Pivetta
This message contains a healthy dose of sarcasm.
Hi Marko and Rowan :)
Me reviewing the PR with that code
*Clicks "Changes required"
[ Please rewrite this statement into easy readable format with an if ]
- Clicks send *
Think what you must, but 6 months when you come back to code like this you
have to stop, look at it hard and figure out what the hell actually happens
there.
Breaks reading flow.One thing I like PHP for is a distinct lack of huge amounts of syntax
sugar.
Take Ruby - it's a hell to read the code. Even Vagrantfile has tons of
results about what syntax for arrays to use and things breaking because you
end up mixing stuff and you get at least 4 different answers to the same
question and it looks like all are correct. Confusing as hell :)What I'm trying to say is some of us choose PHP for it's "there is one
syntax - use it". If people want syntax sugar - there are other languages
that fit that much better. Leave us, peasants, in our peasant non-syntax
sugar world alone :DExactly. One common theme I've been seeing is "We already force our
developers to initialize variables, so, whats the big deal if you have to?"
or "We already force a no-notice environment, so what's the big deal if you
have to?"
If you're already doing it, then why do you feel the need to force others
to? You've proven that it can be done in the current system.
I'm making my prediction now - if this RFC passes, the adoption rate for
PHP 8 is going to be HORRIBLE.
But many of us would also like the language engine to tighten up some of
its extremely relaxed parts that do not fit in modern development
environments and the lowest bar of the code quality rise a bit. Otherwise,
the gap between high-end development and newbies is going to be even bigger
than it is now.
I hire people, that's part of my job. One of the criteria is the approach
to errors/warning/notices. Imagine how that goes.--
Arvīds Godjuks+371 26 851 664
arvids.godjuks@gmail.com
Skype: psihius
Telegram: @psihius https://t.me/psihius
--
Chase Peeler
chasepeeler@gmail.com
On Thu, 12 Sep 2019 at 15:02, Arvids Godjuks arvids.godjuks@gmail.com
wrote:
This message contains a healthy dose of sarcasm.
I think we need less sarcasm on this thread, and more empathy. I'm doing my
best to discuss a real scenario, and how to improve the language for it,
and move away from oh-so-hilarious parodies of each other's positions.
Regards,
Rowan Tommins
[IMSoP]
On Thu, Sep 12, 2019 at 4:02 PM Arvids Godjuks arvids.godjuks@gmail.com
wrote:
чт, 12 сент. 2019 г. в 15:33, Marco Pivetta ocramius@gmail.com:
Hey Rowan,
http://ocramius.github.com/On Thu, Sep 12, 2019 at 3:30 PM Rowan Tommins rowan.collins@gmail.com
wrote:For instance, for undefined array keys, what if we had an operator for
"initialise and retrieve", such as $foo[? 'bar']. Then we could simplify
ugly code like this:if ( ! isset($foo[$key1]) {
$foo[$key1] = [];
}
if ( ! isset($foo[$key1][$key2]) {
$foo[$key1][$key2] = 0;
}
$foo[$key1][$key2]++;With something safe but succinct like this:
$foo[? $key1][? $key2]++;
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
This message contains a healthy dose of sarcasm.
No sarcasm intended: question is about the verbosity and length of a
proper (correct = no warnings/notices/errors, matches type expectations)
checked solution, and I provided a simple one-liner that is both readable
and correct.
You can make what you want out of this, but there was most certainly no
sarcasm.
Marco Pivetta
On Thu, Sep 12, 2019 at 10:20 AM Reindl Harald (privat) harry@rhsoft.net
wrote:
see screenshot, you are the only guy on planet earth whose fukcing first
line is part of the quote above
If you're going to reply to me off list, please at least be polite.
--
Chase Peeler
chasepeeler@gmail.com
In the past I suggested operators like
??++
??+=
for this purpose.
But the [? $key] is even better, because it makes it explicit which array
keys we expect to already exist and which we don't.
$var[$k0][? $k1][? $k2]++;
This is great but the second "?" is redundant isn't it?
Marco Pivetta ocramius@gmail.com schrieb am Do., 12. Sep. 2019, 16:26:
On Thu, Sep 12, 2019 at 4:02 PM Arvids Godjuks arvids.godjuks@gmail.com
wrote:чт, 12 сент. 2019 г. в 15:33, Marco Pivetta ocramius@gmail.com:
Hey Rowan,
http://ocramius.github.com/On Thu, Sep 12, 2019 at 3:30 PM Rowan Tommins rowan.collins@gmail.com
wrote:For instance, for undefined array keys, what if we had an operator for
"initialise and retrieve", such as $foo[? 'bar']. Then we could
simplify
ugly code like this:if ( ! isset($foo[$key1]) {
$foo[$key1] = [];
}
if ( ! isset($foo[$key1][$key2]) {
$foo[$key1][$key2] = 0;
}
$foo[$key1][$key2]++;With something safe but succinct like this:
$foo[? $key1][? $key2]++;
$foo[$key1][$key2] = ($foo[$key1][$key2] ?? 0) + 1;
This message contains a healthy dose of sarcasm.
No sarcasm intended: question is about the verbosity and length of a
proper (correct = no warnings/notices/errors, matches type expectations)
checked solution, and I provided a simple one-liner that is both readable
and correct.You can make what you want out of this, but there was most certainly no
sarcasm.Marco Pivetta
l want to point out that way in which notices and warnings are triggered
when concerning operators, is also inconsistent.
Sometimes a check is done by the function of the operator (or a deeper
function). Other times the operator will simply cast the operand and the
casting produces a notice, warning or error.
As an example; The concatenation operator will implicitly cast anything to
a string. Explicitly casting it has no effect
[ ] . 'abc'; // Notice: Array to string conversion
(string)[ ] . 'abc'; // Notice: Array to string conversion
But arithmetic operators will do a check. Explicitly casting will remove
any warning or error
[ ] * 10; // Fatal error: Unsupported operand types
(int)[ ] * 10; // 0
"22 bikes" * 10; // Notice: A non well formed numeric value encountered
(int)"22 bikes" * 10; // 220
To some extent, the inconsistent error levels come from a different
approach. Even more, there is a big difference between types that can are
cast silently to a non-sensical value and types where any type of warning
or error is given, for seemingly no apparent reason.
Changing the warning levels without addressing this issue doesn't make a
whole lot of sense.
- Arnold
In the past I suggested operators like
??++
??+=
for this purpose.
But the [? $key] is even better, because it makes it explicit which array
keys we expect to already exist and which we don't.
$var[$k0][? $k1][? $k2]++;
This is great but the second "?" is redundant isn't it?
Tekst uit oorspronkelijke berichten weergeven
$var[$k0][? $k1][? $k2]++;
This is great but the second "?" is redundant isn't it?
If the rule is "you cannot read a non-existent array element without ?"
then no: $var[$k0][? $k1] allows you to read that element, and from
context treat it as an array; but that array won't have a key $k2, so
you also need to say that reading that was deliberate, and from
context treat it as an integer.
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]
Hello all
I've noticed a trend in many threads here on the internals list where an RFC is being discussed, but one way or another we always end up with the same offtopic conversation about how PHP should evolve. While I think this is a good conversation to have, I don't think it's beneficial for the RFC process to have the same discussion happening over and over again, effectively having the RFC discussion hijacked by another one. I can only imagine it must be quite difficult for the people working on these RFCs to filter out ontopic from offtopic content.
Here are a few examples:
- Reclassifying engine warnings (https://externals.io/message/106713)
- Short open tags (https://externals.io/message/106384)
- Namespaced scope declares (https://externals.io/message/101323)
- Call-site send by ref (https://externals.io/message/101254)
- PHP 7.4 deprecations (https://externals.io/message/106012)
Maybe someone has a good suggestion on how people can voice their opinion on the future of PHP, without polluting several RFC discussions.
Kinds regards
Brent
Hello all
I've noticed a trend in many threads here on the internals list where an
RFC is being discussed, but one way or another we always end up with the
same offtopic conversation about how PHP should evolve. While I think this
is a good conversation to have, I don't think it's beneficial for the RFC
process to have the same discussion happening over and over again,
effectively having the RFC discussion hijacked by another one. I can only
imagine it must be quite difficult for the people working on these RFCs to
filter out ontopic from offtopic content.Here are a few examples:
- Reclassifying engine warnings (https://externals.io/message/106713)
- Short open tags (https://externals.io/message/106384)
- Namespaced scope declares (https://externals.io/message/101323)
- Call-site send by ref (https://externals.io/message/101254)
- PHP 7.4 deprecations (https://externals.io/message/106012)
Maybe someone has a good suggestion on how people can voice their opinion
on the future of PHP, without polluting several RFC discussions.
Start a new thread (or threads) instead of replying to RFC threads. ?
Kinds regards
Brent
One thing I like PHP for is a distinct lack of huge amounts of syntax
sugar. Take Ruby - it's a hell to read the code.
I think it is unfair to reference Ruby's capabilities as a counter-example for syntax sugar.
The Ruby language allows developers to create what are effectively new language constructs and it is possible in Ruby to write code that cannot be recognized anyone that has not written the language extensions being used.
PHP does not have that capability, thankfully, and I do not think any proposed syntax sugar has any chance of adding those meta-language capabilities into PHP.
Syntax sugar is a good thing when it reduces the need to write boilerplate code for a commonly occurring pattern, especially when the boilerplate code is tedious and potentially error prone because of typos or logic. And it is naturally occurring in language evolution, i.e. newer languages often provide "syntax sugar" for features that are more verbose in earlier languages.
Personally I am not sure I like the proposed syntax, but I am definitely fond of the idea to eliminate the boilerplate code that would be otherwise needed to build a robust solution.
#fwiw
-Mike
P.S. I wrote a blog post in defense of syntactic sugar a while ago.
If you are interested in all the arguments in support of syntactic sugar,
here is the post: https://mikeschinkel.me/2019/in-defense-of-syntactic-sugar/ https://mikeschinkel.me/2019/in-defense-of-syntactic-sugar/
Even Vagrantfile has tons of
results about what syntax for arrays to use and things breaking because you
end up mixing stuff and you get at least 4 different answers to the same
question and it looks like all are correct. Confusing as hell :)What I'm trying to say is some of us choose PHP for it's "there is one
syntax - use it". If people want syntax sugar - there are other languages
that fit that much better. Leave us, peasants, in our peasant non-syntax
sugar world alone :DBut many of us would also like the language engine to tighten up some of
its extremely relaxed parts that do not fit in modern development
environments and the lowest bar of the code quality rise a bit. Otherwise,
the gap between high-end development and newbies is going to be even bigger
than it is now.
I hire people, that's part of my job. One of the criteria is the approach
to errors/warning/notices. Imagine how that goes.--
Arvīds Godjuks+371 26 851 664
arvids.godjuks@gmail.com
Skype: psihius
Telegram: @psihius https://t.me/psihius
Le 12 sept. 2019 à 10:17, Stephen Reay php-lists@koalephant.com a
écrit :I’ve seen a number of people that have concerns about PHP throwing
actual errors (as opposed to notices) because they try to use a
variable/offset that doesn’t exist, and of course there is often a proposal
to have a declare statement or something similar, to allow their “code
style” to run without errors.So, my proposal to the situation is to introduce a single declare that
solves that problem, once and for all.declare(sloppy=1);
This would suppress any errors about undefined variables, array offsets,
would reverse the “bare words" change when encountering an undefined
constant, etc. Heck, for good measure this mode could even re-implement
register_globals and magic_quotes, because why not?
This still forces people to opt-in to something that has been supported for
20+ years, and there isn't even a consensus on it being "sloppy" to begin
with.
If you want to write sloppy code, that is entirely your prerogative, but
please just own it for what it is, and stop pretending that it’s some
herculean task to either define variables/offsets first; or check if
they’re defined; or use an appropriate method to access them that
specifically allows for undefined variables/offsets (i.e. the ?? and ??=
operators)Declare(sloppy=yeah) is not granular enough. To all: please, do understand
that everything is not black or white; this remark is not directed
specifically to that particular issue, this is an attitude I see regularly
on that mailing list.There is no such thing as “one true strict coding standard” and “one
legacy lax coding standard”. For instance:
As time passes, we learn by experience what features were plain blunders
(magic_quotes?), what features should have been more strict for the sake of
catching bugs without imposing too much burden on users, what features
could have been more strict, although that would impose to write lot of
boiler code, etc. This process does not belong exclusively to some past
dark age of sloppy and unsecure coding practices.The degree of wanted strictness vary depending on occasions. For example
when I’m writing a throw-away script, some notices are okay to indicate
possible problems, but I’m not going to write boilerplate code (or, worse,
put a @ in front of everything) just for the sake of silencing them. (But I
certainly do not want stupid things like mistyped constants converted to
string literals.) On the other hand, when I’m writing a critical part of an
application, I am careful to write down everything precisely, and having to
write explicitly and once for all that, yes, this precise variable must
have that default value, is a minimal part of the time passed to write,
re-read and review the code.What??? You mean it's possible to write strict code even when the engine
doesn't force you to? But I got the feeling that wasn't possible and we
needed to force EVERYONE to code this way.
—Claude
--
Chase Peeler
chasepeeler@gmail.com
Le 10 sept. 2019 à 15:31, Nikita Popov nikita.ppv@gmail.com a écrit :
On Wed, Aug 28, 2019 at 11:33 AM Nikita Popov nikita.ppv@gmail.com
wrote:Hi internals,
I think it's time to take a look at our existing warnings & notices in
the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating
a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...https://wiki.php.net/rfc/engine_warnings
Regards,
NikitaHeads up: This RFC may go to vote tomorrow.
Nikita
I have objections to those two reclassifications:
- Undefined offset: %d — Notice → Warning
- Undefined index: %d — Notice → Warning
From experience, having to dutifully initialise each and every key in an
array is burdensome. I understand the rationale of enforcing that in some
coding standard; but whether those particular missing index should be
considered as unexpected (therefore deserving a Warning) is mostly a
question of coding style.This is in principle a similar issue as using uninitialised variables,
which, as noted in this thread, is a perfectly accepted coding pattern in
some languages (the issue being distinct from undeclared variables). I
say “in principle”, because a perfectly reasonable coding style may choose
to enforce initialisation of variables, but not of array keys.PHP has the advantage of supporting various coding styles. We should give
the opportunity to the users to say declaratively (and precisely) what, in
their coding style, is considered as acceptable, e.g.declare(
uninitialized_variables: error
uninitilalized_index: none
);of course, possibly at a package-level declare. That would, for example,
enable people to place legacy code in lax mode and chose a stricter mode
for new code, even letting the precise notion of strictness vary with
fashion without having to review working code written two years ago.That said, as long as those issues are handled as errors (as in:
set_error_handler()
) rather than exceptions, one may write a proper error
handler that does the distinction (I do that). However, an error handler
has the disadvantage of being global, making difficult the integration of
code written with differing coding standards.—Claude
Hi Claude,
I have split off the question of undefined array keys into a separate
section, which will be voted separately.
I generally agree that ignoring undefined array key notices can be a
legitimate coding style choice (while I would very much disagree that the
same is true for undefined variables) -- though ultimately I think it is
best to handle this with a custom error handler (which can check whether
the error originated from your own codebase), rather than through a blanket
suppression of notices. In line with that thinking I don't think it matters
overly much whether it's a notice or warning for the purposes of
suppression. But I also don't feel particularly strongly about having this
case as a warning either, especially with the error_reporting=E_ALL default
in PHP 8.
Nikita
Hi internals
This maybe a little bit late but I would like to propose alternative to
this RFC.
What if we add strict_errors
declare to make every function/method in
files that declared strict_errors
throw ErrorException on Notice/Warning.
Example:
File: Test.php
<?php
declare(strict_errors=1); // does not support block declare like
'strict_type'
class Test {
public function __construct()
{
echo $a; // ErrorException will be thrown from here
}
}
File: main.php
<?php
require 'Test.php';
$test = new Test(); // Fatal error: Uncaught ErrorException: Undefined
variable: a
But if set_error_handler()
is in use nothing will happen.
File: main.php
<?php
require 'Test.php';
set_error_handler(function () {
});
$test = new Test(); // silent
I've just made a naive implementation to demonstrate this approach at
https://github.com/webdevxp/php-src.
What I've done was just adding new ZEND_ACC_STRICT_ERRORS flag to top level
function and modified php_error_cb
to check if there is a caller with
strict_errors
defined. (by simply checking EG(current_execute_data)
and
its all prev_execute_data
)
I think this approach might satify both 'strict camp' and 'bc camp'.
P.S. I myself agree with this RFC and would vote YES if I can vote. And I'm
grateful for Nikita's (and others) contributions that make PHP awesome
today.
Cheers :)
Hi internals,
I think it's time to take a look at our existing warnings & notices in the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...https://wiki.php.net/rfc/engine_warnings
Regards,
Nikita
https://jaxenter.com/php-tiobe-sept-2019-162096.html
I think this is one of those things we get from voting no...
I might be wrong anyways :-?
Hi internals
This maybe a little bit late but I would like to propose alternative to
this RFC.What if we add
strict_errors
declare to make every function/method in
files that declaredstrict_errors
throw ErrorException on Notice/Warning.Example:
File: Test.php
<?php
declare(strict_errors=1); // does not support block declare like
'strict_type'class Test {
public function __construct()
{
echo $a; // ErrorException will be thrown from here
}
}File: main.php
<?php
require 'Test.php';
$test = new Test(); // Fatal error: Uncaught ErrorException: Undefined
variable: aBut if
set_error_handler()
is in use nothing will happen.File: main.php
<?php
require 'Test.php';
set_error_handler(function () {});
$test = new Test(); // silentI've just made a naive implementation to demonstrate this approach at
https://github.com/webdevxp/php-src.
What I've done was just adding new ZEND_ACC_STRICT_ERRORS flag to top level
function and modifiedphp_error_cb
to check if there is a caller with
strict_errors
defined. (by simply checkingEG(current_execute_data)
and
its allprev_execute_data
)I think this approach might satify both 'strict camp' and 'bc camp'.
P.S. I myself agree with this RFC and would vote YES if I can vote. And I'm
grateful for Nikita's (and others) contributions that make PHP awesome
today.Cheers :)
Hi internals,
I think it's time to take a look at our existing warnings & notices in
the
engine, and think about whether their current classification is still
appropriate. Error conditions like "undefined variable" only generating a
notice is really quite mind-boggling.I've prepared an RFC with some suggested classifications, though there's
room for bikeshedding here...https://wiki.php.net/rfc/engine_warnings
Regards,
Nikita
I am 100% behind the exception proposals, however I did want to discuss
the warnings.
I am personally of the belief that there should be a distinction made
between notices / warnings issued by the engine, and those issued by
extensions, including standard.
I am one of a large number of developers that enforces a "No notice or
warning" requirement on their codebases. To this end I use a global
error handler that converts ANY notice or error to an \Error exception
(within our specific code, so excluding anything in /vendor and the likes).
This does however, effect function calls as well, and it's less ideal to
have function calls throwing Error, something derived from Exception
would make more sense. The issue is which is which.
If this does pass, I was wondering if there would be any appetite for
re-using the E_CORE_XXX error error codes specifically to refer to ALL
engine warnings, not just those at startup.
Alternatively, the passing of a bitflag to indicate they came from the
engine while still preserving the original bit, although that may be
more of a BC break due to requiring bitwise mask comparison in existing
handlers.
Either way, this this would allow easily differentiating engine warnings
that will become more prominent in this RFC, with those contained in
PHP_FUNCTION scope.
--
Mark Randall