Hi everybody,
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?
It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it off
until 7.1.
Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises <https://paragonie.com
That's exactly what isset() does. isset/empty never raise errors.
On Tue, Aug 25, 2015 at 11:09 PM, Scott Arciszewski scott@paragonie.com
wrote:
Hi everybody,
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it off
until 7.1.Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises <https://paragonie.com
On Tue, Aug 25, 2015 at 11:11 PM, Sherif Ramadan
theanomaly.is@gmail.com wrote:
That's exactly what isset() does. isset/empty never raise errors.
On Tue, Aug 25, 2015 at 11:09 PM, Scott Arciszewski scott@paragonie.com
wrote:Hi everybody,
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it off
until 7.1.Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises https://paragonie.com--
http://phpsadness.com/sad/28
https://3v4l.org/2vrKG
Not quite.
Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises <https://paragonie.com
Yes, because all undefined variables in PHP are implicitly null. As far as
PHP is concerned, if it's null, it's by definition not defined. Also,
still not seeing where a NOTICE is involved here? Those functions never
give errors.
What is the usefulness of a function that merely returns true when a
variable is null?
On Tue, Aug 25, 2015 at 11:13 PM, Scott Arciszewski scott@paragonie.com
wrote:
On Tue, Aug 25, 2015 at 11:11 PM, Sherif Ramadan
theanomaly.is@gmail.com wrote:That's exactly what isset() does. isset/empty never raise errors.
On Tue, Aug 25, 2015 at 11:09 PM, Scott Arciszewski <scott@paragonie.com
wrote:
Hi everybody,
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it off
until 7.1.Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises https://paragonie.com--
http://phpsadness.com/sad/28
https://3v4l.org/2vrKGNot quite.
Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises <https://paragonie.com
Because $x exists.
https://3v4l.org/kUJtP
Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises
On Tue, Aug 25, 2015 at 11:16 PM, Sherif Ramadan
theanomaly.is@gmail.com wrote:
Yes, because all undefined variables in PHP are implicitly null. As far as
PHP is concerned, if it's null, it's by definition not defined. Also,
still not seeing where a NOTICE is involved here? Those functions never give
errors.What is the usefulness of a function that merely returns true when a
variable is null?On Tue, Aug 25, 2015 at 11:13 PM, Scott Arciszewski scott@paragonie.com
wrote:On Tue, Aug 25, 2015 at 11:11 PM, Sherif Ramadan
theanomaly.is@gmail.com wrote:That's exactly what isset() does. isset/empty never raise errors.
On Tue, Aug 25, 2015 at 11:09 PM, Scott Arciszewski
scott@paragonie.com
wrote:Hi everybody,
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it off
until 7.1.Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises https://paragonie.com--
http://phpsadness.com/sad/28
https://3v4l.org/2vrKGNot quite.
Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises <https://paragonie.com
I get that it exists. I'm asking what is the usefulness of having a
function that tells you the variable is null? In theory this sounds great
and is actually very doable by checking the symbol table for the hash.
However, in practice, who actually has a use for this? Null is a special
value in PHP, so if you're assigning it to a variable explicitly you should
already know you've initialized that variable and can safely rely on if ($x
=== null) in your code.
I'm not confused about the differences. I'm questioning the usefulness of
such a function.
On Tue, Aug 25, 2015 at 11:18 PM, Scott Arciszewski scott@paragonie.com
wrote:
Because $x exists.
https://3v4l.org/kUJtP
Scott Arciszewski
Chief Development Officer
Paragon Initiative EnterprisesOn Tue, Aug 25, 2015 at 11:16 PM, Sherif Ramadan
theanomaly.is@gmail.com wrote:Yes, because all undefined variables in PHP are implicitly null. As far
as
PHP is concerned, if it's null, it's by definition not defined. Also,
still not seeing where a NOTICE is involved here? Those functions never
give
errors.What is the usefulness of a function that merely returns true when a
variable is null?On Tue, Aug 25, 2015 at 11:13 PM, Scott Arciszewski <scott@paragonie.com
wrote:
On Tue, Aug 25, 2015 at 11:11 PM, Sherif Ramadan
theanomaly.is@gmail.com wrote:That's exactly what isset() does. isset/empty never raise errors.
On Tue, Aug 25, 2015 at 11:09 PM, Scott Arciszewski
scott@paragonie.com
wrote:Hi everybody,
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it off
until 7.1.Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises https://paragonie.com--
http://phpsadness.com/sad/28
https://3v4l.org/2vrKGNot quite.
Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises <https://paragonie.com
You are probably looking for something like array_key_exists($varName,
get_defined_vars());
: https://3v4l.org/XagEA
Marco Pivetta
I get that it exists. I'm asking what is the usefulness of having a
function that tells you the variable is null? In theory this sounds great
and is actually very doable by checking the symbol table for the hash.
However, in practice, who actually has a use for this? Null is a special
value in PHP, so if you're assigning it to a variable explicitly you should
already know you've initialized that variable and can safely rely on if ($x
=== null) in your code.I'm not confused about the differences. I'm questioning the usefulness of
such a function.On Tue, Aug 25, 2015 at 11:18 PM, Scott Arciszewski scott@paragonie.com
wrote:Because $x exists.
https://3v4l.org/kUJtP
Scott Arciszewski
Chief Development Officer
Paragon Initiative EnterprisesOn Tue, Aug 25, 2015 at 11:16 PM, Sherif Ramadan
theanomaly.is@gmail.com wrote:Yes, because all undefined variables in PHP are implicitly null. As far
as
PHP is concerned, if it's null, it's by definition not defined. Also,
still not seeing where a NOTICE is involved here? Those functions never
give
errors.What is the usefulness of a function that merely returns true when a
variable is null?On Tue, Aug 25, 2015 at 11:13 PM, Scott Arciszewski <
scott@paragonie.comwrote:
On Tue, Aug 25, 2015 at 11:11 PM, Sherif Ramadan
theanomaly.is@gmail.com wrote:That's exactly what isset() does. isset/empty never raise errors.
On Tue, Aug 25, 2015 at 11:09 PM, Scott Arciszewski
scott@paragonie.com
wrote:Hi everybody,
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if
the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it
off
until 7.1.Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises https://paragonie.com--
http://phpsadness.com/sad/28
https://3v4l.org/2vrKGNot quite.
Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises <https://paragonie.com
Hi!
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?
Not sure what the use case would be for this. For most practical
purposes, isset/empty look completely fine.
It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it off
until 7.1.
It is simple, but not everything that is simple should be done.
Especially when we talking about adding core functions.
--
Stas Malyshev
smalyshev@gmail.com
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?Not sure what the use case would be for this. For most practical
purposes, isset/empty look completely fine.
As a web (not core) developer I've been bitten by this a couple of times.
Both were fairly quick to identify/fix, but enough to be a little annoying.
If you want some example of where I got this wrong...
I have a config array for defining the websites CSP header, it starts something like:
$csp_directives = array(
'default-src' => array("'none'"),
'form-action' => array("'self'"),
'style-src' => array("'self'"),
'img-src' => array("'self'"),
'script-src' => array("'self'"),
);
Depending on the website I may then add a key to define the 'report-uri', or I may set it to NULL
to say that I don't want one. If it remains unset (key does not exist), then the framework provides a default. At first I used an isset() check, forgetting that setting to NULL
would not be seen as "set".
When creating a URL builder that allowed the query string to be passed in as an array. If it defaulted to the current URL (with its query string values), then the passed in array might tell it to explicitly remove certain values by setting them to NULL. When I first wrote this, I did an isset() check when adding the current URL's query string to the array of query string values (which take precedence).
Neither were major problems, just a slight annoyance (i.e. identified and fixed before I committed the code). But I'm normally using an isset() as the proposed exists() function would work.
Hi!
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?Not sure what the use case would be for this. For most practical
purposes, isset/empty look completely fine.It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it off
until 7.1.It is simple, but not everything that is simple should be done.
Especially when we talking about adding core functions.--
Stas Malyshev
smalyshev@gmail.com
Craig Francis wrote on 26/08/2015 12:23:
If you want some example of where I got this wrong...
I have a config array [...]
When creating a URL builder that allowed the query string to be passed in as an array [...]
Neither were major problems, just a slight annoyance (i.e. identified and fixed before I committed the code). But I'm normally using an isset() as the proposed exists() function would work.
Both of these example involve not an undefined variable, but an
undefined array key, which is a much less controversial scenario.
Fortunately, the function you are looking for already exists:
http://php.net/array_key_exists
Regards,
Rowan Collins
[IMSoP]
Fortunately, the function you are looking for already exists: http://php.net/array_key_exists
It does, although I seem to have edited that out of my reply... was trying to keep it short ;-)
At the moment I'm out of examples (bit busy at the moment), but I do know that when I'm doing an isset() check, I'm really wanting to know if the variable (or key) exists, where NULL
may be a perfectly valid value.
So there is a slight annoyance (and typically a quick fix) to identify if the variable has just been set to NULL.
Craig Francis wrote on 26/08/2015 12:23:
If you want some example of where I got this wrong...
I have a config array [...]
When creating a URL builder that allowed the query string to be passed in as an array [...]
Neither were major problems, just a slight annoyance (i.e. identified and fixed before I committed the code). But I'm normally using an isset() as the proposed exists() function would work.
Both of these example involve not an undefined variable, but an undefined array key, which is a much less controversial scenario.
Fortunately, the function you are looking for already exists: http://php.net/array_key_exists
Regards,
Rowan Collins
[IMSoP]
Craig Francis wrote on 26/08/2015 14:53:
Fortunately, the function you are looking for already exists: http://php.net/array_key_exists
It does, although I seem to have edited that out of my reply... was trying to keep it short ;-)
You could have kept the reply even shorter by omitting examples for
which the language already provides the solution ;)
At the moment I'm out of examples (bit busy at the moment), but I do know that when I'm doing an isset() check, I'm really wanting to know if the variable (or key) exists
Stop. As soon as you say "or key" you completely defeat your argument.
The whole thing is ONLY worth discussing if you can come up with an
example of an actual variable having unknown existence.
where
NULL
may be a perfectly valid value.
It's not that NULL
isn't a valid value; it's that "doesn't exist" isn't
a meaningful state for a variable. It's like checking if the current
line number is greater than 100, it shouldn't mean anything to the
compiled program. See the SO answer I linked earlier for more thought
experiments along these lines.
Regards,
Rowan Collins
[IMSoP]
Craig Francis wrote on 26/08/2015 14:53:
Fortunately, the function you are looking for already exists: http://php.net/array_key_exists
It does, although I seem to have edited that out of my reply... was trying to keep it short ;-)You could have kept the reply even shorter by omitting examples for which the language already provides the solution ;)
I provide examples to help explain that I (and I suspect most developers) default to using isset which works on either.
Just because there is a function, which does not exactly roll off the tongue (plus the fun of the needle/haystack ordering issue), does not mean it gets used (even if it is the correct thing to use).
At the moment I'm out of examples (bit busy at the moment), but I do know that when I'm doing an isset() check, I'm really wanting to know if the variable (or key) exists
Stop. As soon as you say "or key" you completely defeat your argument. The whole thing is ONLY worth discussing if you can come up with an example of an actual variable having unknown existence.
I say "or key" because developers use the isset function on both $var and $var['key']... yes, I know they are different, but when you are coding in PHP an isset check is an isset check (well it isn't, because the variable may technically exist).
If this is a problem, maybe PHP should raise a notice when isset is used on arrays?
where
NULL
may be a perfectly valid value.It's not that
NULL
isn't a valid value; it's that "doesn't exist" isn't a meaningful state for a variable. It's like checking if the current line number is greater than 100, it shouldn't mean anything to the compiled program. See the SO answer I linked earlier for more thought experiments along these lines.
I think you have been spending too much time in C.
Most of the PHP code bases I've worked on set variables to NULL
at some point (and they are not calling unset, because that isn't the intention).
On Wed, Aug 26, 2015 at 12:07 PM, Craig Francis craig@craigfrancis.co.uk
wrote:
Craig Francis wrote on 26/08/2015 14:53:
On 26 Aug 2015, at 12:36, Rowan Collins rowan.collins@gmail.com
wrote:
where
NULL
may be a perfectly valid value.It's not that
NULL
isn't a valid value; it's that "doesn't exist" isn't
a meaningful state for a variable. It's like checking if the current line
number is greater than 100, it shouldn't mean anything to the compiled
program. See the SO answer I linked earlier for more thought experiments
along these lines.I think you have been spending too much time in C.
Most of the PHP code bases I've worked on set variables to
NULL
at some
point (and they are not calling unset, because that isn't the intention).
I think there is a misunderstanding here that is drawing this out.
Assigning meaning to NULL
in any language is wrong. That is why it should
be treated as if the variable didn't exist and isset is appropriate.
This is a common pitfall in database design as well where you can allow
NULL
as a field value. Assigning meaning to to that NULL
value can quickly
lead to problem.
Craig Francis wrote on 26/08/2015 18:07:
I provide examples to help explain that I (and I suspect most developers) default to using isset which works on either.
Just because there is a function, which does not exactly roll off the tongue (plus the fun of the needle/haystack ordering issue), does not mean it gets used (even if it is the correct thing to use).
That's all very well, but what is the Internals community supposed to do
about it? Does the documentation need to be improved to point out that
there is a better function to use for this case?
I say "or key" because developers use the isset function on both $var and $var['key']... yes, I know they are different, but when you are coding in PHP an isset check is an isset check (well it isn't, because the variable may technically exist).
If this is a problem, maybe PHP should raise a notice when isset is used on arrays?
It's only a problem in the same way that using file_exists()
is a
problem when you actually wanted the functionality of is_readable()
-
both functions exist, and it's not the language's responsibility to
guess which you meant.
where
NULL
may be a perfectly valid value.
It's not thatNULL
isn't a valid value; it's that "doesn't exist" isn't a meaningful state for a variable. It's like checking if the current line number is greater than 100, it shouldn't mean anything to the compiled program. See the SO answer I linked earlier for more thought experiments along these lines.I think you have been spending too much time in C.
Most of the PHP code bases I've worked on set variables to
NULL
at some point (and they are not calling unset, because that isn't the intention).
Perhaps my double negative made it unclear, so I will restate: there is
nothing wrong with setting a variable to NULL. There is also nothing
wrong with calling unset() on a plain variable, e.g. to make it obvious
to readers of the code that this variable should not be used below this
point.
There IS something wrong with any code which needs to distinguish which
of those two things happened, at run-time, because such code would be
incredibly fragile and hard to follow.
You could, if you wanted, emulate a boolean variable by using $foo=null
for true, and unset($foo) for false, but why not simply have a boolean
variable?
[Incidentally, I know barely any C, but program PHP for a living.]
Regards,
Rowan Collins
[IMSoP]
Hi Rowan, Ryan, James, Bishop, Stas, Lester,
I've been giving this some thought over the weekend, and I agree with what you are all saying, but I think there is an element of confusion in the PHP programming community that needs to be addressed (somehow).
Yes, we probably should not be giving special meaning to NULL, as James mentions (although I probably still will).
And to be fair, I still can't think of an example where isset() can be used on a standard variable. All my examples are really array based, and better addressed with array_key_exists()
- where Rowan does a great job of explaining the different examples on stackoverflow:
http://stackoverflow.com/a/18646568/2908724
Trying to get to route of the confusion though, I think it might be down to how the code can be read. So if we take:
<?php
$a = 1;
$b = NULL;
var_dump($a);
var_dump($b);
var_dump($c);
var_dump(isset($a));
var_dump(isset($b));
var_dump(isset($c));
?>
Or using an array instead:
<?php
$v['a'] = 1;
$v['b'] = NULL;
var_dump($v['a']);
var_dump($v['b']);
var_dump($v['c']);
var_dump(isset($v['a']));
var_dump(isset($v['b']));
var_dump(isset($v['c']));
?>
In both cases (and ignoring the undefined variable error), we get:
int(1)
NULL
NULL
bool(true)
bool(false)
bool(false)
But if we ignore the manual for a minute:
I think a good comparison to what that code reads as, vs what PHP does, can be summarised as:
Read as: The variable is set (exists).
Executed as: The variables value is set.
Where NULL
is not considered a set value.
So when we have:
if (isset($v['a'])) {
}
It's not saying that the key 'a' is set (exists) on the array $v.
Instead its saying that the key 'a' has a set value (not NULL) on the array $v.
Where this is made more of a common problem because there are many array_* functions, and they rarely come to mind when your not thinking of an array like operation.
This situation might be improved by re-wording the manual a bit.
Having headings like "This also work[s] for elements in arrays", makes it sound all inclusive and the function to use.
Whereas I'm starting to get the feeling that isset() is actually a function that probably should be avoided (I'll skip this tangent for now).
Personally I still like the idea of an exists(), because I feel that is how many programmers treat and use the isset() function - simply because they do use NULL
as a valid value, and either haven't read the manual, or forget the exception that is mentioned on line 1 (something I've done a couple of times).
Although I realise it will take many years before anyone can start using it.
Craig
Craig Francis wrote on 26/08/2015 18:07:
I provide examples to help explain that I (and I suspect most developers) default to using isset which works on either.
Just because there is a function, which does not exactly roll off the tongue (plus the fun of the needle/haystack ordering issue), does not mean it gets used (even if it is the correct thing to use).
That's all very well, but what is the Internals community supposed to do about it? Does the documentation need to be improved to point out that there is a better function to use for this case?
I say "or key" because developers use the isset function on both $var and $var['key']... yes, I know they are different, but when you are coding in PHP an isset check is an isset check (well it isn't, because the variable may technically exist).
If this is a problem, maybe PHP should raise a notice when isset is used on arrays?
It's only a problem in the same way that using
file_exists()
is a problem when you actually wanted the functionality ofis_readable()
- both functions exist, and it's not the language's responsibility to guess which you meant.where
NULL
may be a perfectly valid value.
It's not thatNULL
isn't a valid value; it's that "doesn't exist" isn't a meaningful state for a variable. It's like checking if the current line number is greater than 100, it shouldn't mean anything to the compiled program. See the SO answer I linked earlier for more thought experiments along these lines.I think you have been spending too much time in C.
Most of the PHP code bases I've worked on set variables to
NULL
at some point (and they are not calling unset, because that isn't the intention).Perhaps my double negative made it unclear, so I will restate: there is nothing wrong with setting a variable to NULL. There is also nothing wrong with calling unset() on a plain variable, e.g. to make it obvious to readers of the code that this variable should not be used below this point.
There IS something wrong with any code which needs to distinguish which of those two things happened, at run-time, because such code would be incredibly fragile and hard to follow.
You could, if you wanted, emulate a boolean variable by using $foo=null for true, and unset($foo) for false, but why not simply have a boolean variable?
[Incidentally, I know barely any C, but program PHP for a living.]
Regards,
Rowan Collins
[IMSoP]
Hi Rowan, Ryan, James, Bishop, Stas, Lester,
I've been giving this some thought over the weekend, and I agree with what you are all saying, but I think there is an element of confusion in the PHP programming community that needs to be addressed (somehow).
Yes, we probably should not be giving special meaning to NULL, as James mentions (although I probably still will).
And to be fair, I still can't think of an example where isset() can be used on a standard variable. All my examples are really array based, and better addressed with
array_key_exists()
- where Rowan does a great job of explaining the different examples on stackoverflow:http://stackoverflow.com/a/18646568/2908724
Trying to get to route of the confusion though, I think it might be down to how the code can be read. So if we take:
<?php
$a = 1;
$b = NULL;
var_dump($a);
var_dump($b);
var_dump($c);
var_dump(isset($a));
var_dump(isset($b));
var_dump(isset($c));
?>Or using an array instead:
<?php
$v['a'] = 1;
$v['b'] = NULL;
var_dump($v['a']);
var_dump($v['b']);
var_dump($v['c']);
var_dump(isset($v['a']));
var_dump(isset($v['b']));
var_dump(isset($v['c']));
?>In both cases (and ignoring the undefined variable error), we get:
int(1)
NULL
NULL
bool(true)
bool(false)
bool(false)But if we ignore the manual for a minute:
I think a good comparison to what that code reads as, vs what PHP does, can be summarised as:
Read as: The variable is set (exists).
Executed as: The variables value is set.
Where
NULL
is not considered a set value.So when we have:
if (isset($v['a'])) {
}It's not saying that the key 'a' is set (exists) on the array $v.
Instead its saying that the key 'a' has a set value (not NULL) on the array $v.
Where this is made more of a common problem because there are many array_* functions, and they rarely come to mind when your not thinking of an array like operation.
This situation might be improved by re-wording the manual a bit.
Having headings like "This also work[s] for elements in arrays", makes it sound all inclusive and the function to use.
Whereas I'm starting to get the feeling that isset() is actually a function that probably should be avoided (I'll skip this tangent for now).
Personally I still like the idea of an exists(), because I feel that is how many programmers treat and use the isset() function - simply because they do use
NULL
as a valid value, and either haven't read the manual, or forget the exception that is mentioned on line 1 (something I've done a couple of times).Although I realise it will take many years before anyone can start using it.
Craig
Craig Francis wrote on 26/08/2015 18:07:
I provide examples to help explain that I (and I suspect most developers) default to using isset which works on either.
Just because there is a function, which does not exactly roll off the tongue (plus the fun of the needle/haystack ordering issue), does not mean it gets used (even if it is the correct thing to use).
That's all very well, but what is the Internals community supposed to do about it? Does the documentation need to be improved to point out that there is a better function to use for this case?
I say "or key" because developers use the isset function on both $var and $var['key']... yes, I know they are different, but when you are coding in PHP an isset check is an isset check (well it isn't, because the variable may technically exist).
If this is a problem, maybe PHP should raise a notice when isset is used on arrays?
It's only a problem in the same way that using
file_exists()
is a problem when you actually wanted the functionality ofis_readable()
- both functions exist, and it's not the language's responsibility to guess which you meant.where
NULL
may be a perfectly valid value.
It's not thatNULL
isn't a valid value; it's that "doesn't exist" isn't a meaningful state for a variable. It's like checking if the current line number is greater than 100, it shouldn't mean anything to the compiled program. See the SO answer I linked earlier for more thought experiments along these lines.I think you have been spending too much time in C.
Most of the PHP code bases I've worked on set variables to
NULL
at some point (and they are not calling unset, because that isn't the intention).Perhaps my double negative made it unclear, so I will restate: there is nothing wrong with setting a variable to NULL. There is also nothing wrong with calling unset() on a plain variable, e.g. to make it obvious to readers of the code that this variable should not be used below this point.
There IS something wrong with any code which needs to distinguish which of those two things happened, at run-time, because such code would be incredibly fragile and hard to follow.
You could, if you wanted, emulate a boolean variable by using $foo=null for true, and unset($foo) for false, but why not simply have a boolean variable?
[Incidentally, I know barely any C, but program PHP for a living.]
Regards,
Rowan Collins
[IMSoP]--
--
The pieces are already in place, if this is a desired feature we just
have to bring them together.
-
array_key_exists()
-
get_defined_vars()
I do agree that it would be years before anyone got to use it (either
7.1.0 or 8.0.0). I don't see that as a bad thing, this was low-hanging
fruit.
Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises <https://paragonie.com
Personally I still like the idea of an exists(), because I feel that is how many programmers treat and use the isset() function - simply because they do use
NULL
as a valid value, and either haven't read the manual, or forget the exception that is mentioned on line 1 (something I've done a couple of times).Although I realise it will take many years before anyone can start using it.
For those of us starting from a base of SQL data, NULL
has always been
'not set' and so a binary field can have three values 'yes', 'no' and
'don't know' so when that data is transferred into PHP it has always
been natural to maintain that distinction so NULL
=== not set.
That this data exists in an array in PHP is a natural development, but
the object orientated/class approach would be that the data is loaded
into an object and the values in that object are no longer considered as
array elements, but discrete variables with all the overheads of getters
and setters, so an 'isset' to check if the value HAS been converted from
NULL
to a live value is what is NOW the preferred style of working?
While the older style of working would simply directly read the elements
of the array?
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Personally I still like the idea of an exists(), because I feel that is how many programmers treat and use the isset() function - simply because they do use
NULL
as a valid value, and either haven't read the manual, or forget the exception that is mentioned on line 1 (something I've done a couple of times).
I'm still not sure how exists() would be anything other than an alias
for array_key_exists()
.
Once again, this is NOT about "using NULL
as a valid value"; it's about
"using a variable's NON-EXISTENCE as a valid state". I think that is the
fundamental mistake people make - they think the "quirk" is that isset()
returns false for a null value, when that is the most rational part of
it. The "quirk" is that you don't get a warning when passing a
completely undefined variable to isset().
Obviously, that's not something that's likely to change, but as you say,
what we are really testing is "the value pointed at by some identifier".
In an array, that identifier can be dynamic, but in plain variable
scope, that identifier is something you the programmer have defined long
before the program executed, so its existence is never in question.
Looked at that way, the handling of unitialised variables is just a
side-effect of the handling of NULLs, since all unitialised variables
have a default/implicit value of NULL.
Regards,
--
Rowan Collins
[IMSoP]
I'm still not sure how exists() would be anything other than an alias for
array_key_exists()
.
I think that is the case as well (ish).
But considering that isset() seems to be the function that is used most of the time, I want to consider why that is the case.
Before last week, if someone asked me to write some code to see if a variable (or key) exists, I would have simply used isset() without thinking (this being a problem if the variable was set to NULL).
Whereas, if I was told to check if the variable was NULL, I would do an "$a === NULL" or is_null()
.
It might just be due to the functions name length or usage, while wanting to avoid undefined variable notices:
<?php
$search = (isset($_GET['q']) ? $_GET['q'] : '');
$search = (array_key_exists('q', $_GET) ? $_GET['q'] : '');
?>
The second one does also represent the variable in a different way (grep for "$_GET['q']", where it only appears 3 times in that code).
And the second one does not really check for the existence of $_GET, which in this case is probably ok.
Craig
Personally I still like the idea of an exists(), because I feel that is how many programmers treat and use the isset() function - simply because they do use
NULL
as a valid value, and either haven't read the manual, or forget the exception that is mentioned on line 1 (something I've done a couple of times).I'm still not sure how exists() would be anything other than an alias for
array_key_exists()
.Once again, this is NOT about "using
NULL
as a valid value"; it's about "using a variable's NON-EXISTENCE as a valid state". I think that is the fundamental mistake people make - they think the "quirk" is that isset() returns false for a null value, when that is the most rational part of it. The "quirk" is that you don't get a warning when passing a completely undefined variable to isset().Obviously, that's not something that's likely to change, but as you say, what we are really testing is "the value pointed at by some identifier". In an array, that identifier can be dynamic, but in plain variable scope, that identifier is something you the programmer have defined long before the program executed, so its existence is never in question.
Looked at that way, the handling of unitialised variables is just a side-effect of the handling of NULLs, since all unitialised variables have a default/implicit value of NULL.
Regards,
--
Rowan Collins
[IMSoP]
Craig Francis wrote on 02/09/2015 10:06:
I'm still not sure how exists() would be anything other than an alias for
array_key_exists()
.I think that is the case as well (ish).
But considering that isset() seems to be the function that is used most of the time, I want to consider why that is the case.
Before last week, if someone asked me to write some code to see if a variable (or key) exists,
Again, you insist on drawing a false equivalence to the different
concepts of variable and array key. This makes the following sentence
really easy to dismiss:
I would have simply used isset() without thinking (this being a problem if the variable was set to NULL).
No, it wouldn't be a problem if a VARIABLE was set to null, because
there is no practical difference between an unset variable and one set
to null, so you never need to ask which you have.
It would be a problem if you were testing for the existence of an
array key. There should probably be a prominent link to
array_key_exists()
and property_exists()
on the isset() manual page
The second one does also represent the variable in a different way (grep for "$_GET['q']", where it only appears 3 times in that code).
This is a more reasonable point, and I was pondering whether it would be
possible to allow a more natural syntax.
It would probably require a lot of "magic" in the engine, though,
because it would have to parse exists($foo['bar']['baz']) in some
special way to know that it needed to first find the value of
$foo['bar'], and then do an existence check for key 'baz', rather than
just treating the whole thing as an expression to resolve before
exists() was called. Evaluating things like exists(foo()[ bar() ])
correctly might get messy, as would giving a meaningful result or error
if you wrote exists($foo['bar'] + 1).
And the second one does not really check for the existence of $_GET, which in this case is probably ok.
I'm not really sure what you mean by this.
In summary, I don't think any language change is needed here, but
documentation needs to be improved. I will have a go at drafting a new
intro for the isset() page when/if I get time.
Regards,
Rowan Collins
[IMSoP]
In summary, I don't think any language change is needed here, but documentation needs to be improved. I will have a go at drafting a new intro for the isset() page when/if I get time.
Maybe... personally I don't see why anyone would be performing operations such as:
exists($foo['bar'] + 1)
In the same way that isset($a + 1)
results in a parse error.
But then again, I don't think it's a quirk that "you don't get a warning when passing a completely undefined variable to isset()", as I don't see isset() as a normal function.
If you do treat is as a normal function, you might as well be using is_null()
or "=== NULL".
For example, I think its quite common for MVC style frameworks to check if a variable exists (with isset) in a View (e.g. checking if a paginator exists after printing the table of results).
With the exists($foo['bar']['baz'])
example, I just see that as a simple: if $foo exists, and contains the key 'bar', and contains the key 'baz' (no need to check values).
Like isset() I see exists() as a special function that isn't passing a variable in, but PHP doing some analysis of the thing in the brackets.
Craig
Craig Francis wrote on 02/09/2015 10:06:
I'm still not sure how exists() would be anything other than an alias for
array_key_exists()
.I think that is the case as well (ish).
But considering that isset() seems to be the function that is used most of the time, I want to consider why that is the case.
Before last week, if someone asked me to write some code to see if a variable (or key) exists,
Again, you insist on drawing a false equivalence to the different concepts of variable and array key. This makes the following sentence really easy to dismiss:
I would have simply used isset() without thinking (this being a problem if the variable was set to NULL).
No, it wouldn't be a problem if a VARIABLE was set to null, because there is no practical difference between an unset variable and one set to null, so you never need to ask which you have.
It would be a problem if you were testing for the existence of an array key. There should probably be a prominent link to
array_key_exists()
andproperty_exists()
on the isset() manual pageThe second one does also represent the variable in a different way (grep for "$_GET['q']", where it only appears 3 times in that code).
This is a more reasonable point, and I was pondering whether it would be possible to allow a more natural syntax.
It would probably require a lot of "magic" in the engine, though, because it would have to parse exists($foo['bar']['baz']) in some special way to know that it needed to first find the value of $foo['bar'], and then do an existence check for key 'baz', rather than just treating the whole thing as an expression to resolve before exists() was called. Evaluating things like exists(foo()[ bar() ]) correctly might get messy, as would giving a meaningful result or error if you wrote exists($foo['bar'] + 1).
And the second one does not really check for the existence of $_GET, which in this case is probably ok.
I'm not really sure what you mean by this.
In summary, I don't think any language change is needed here, but documentation needs to be improved. I will have a go at drafting a new intro for the isset() page when/if I get time.
Regards,
Rowan Collins
[IMSoP]
But then again, I don't think it's a quirk that "you don't get a
warning when passing a completely undefined variable to isset()", as I
don't see isset() as a normal function.
What I meant is that people seem to interpret isset() as having a special case for null values, and want that special case to go away. I was suggesting you could instead see it as a version of is_null with a special case to stop it complaining about non-existent variables. This makes sense, since in practice a "non-existent" variable (note: not array item or property) always has the value "null".
It's also a "quirk" in the sense that suppressing that warning for a plain variable is an odd thing to want - if you've assigned meaning to that variable you should be initialising it somewhere so that your code is more readable and less fragile.
With the
exists($foo['bar']['baz'])
example, I just see that as a
simple: if $foo exists, and contains the key 'bar', and contains the
key 'baz' (no need to check values).Like isset() I see exists() as a special function that isn't passing a
variable in, but PHP doing some analysis of the thing in the brackets.
OK, thinking about it some more, I can see it would be convenient to have a special syntax for array_key_exists()
which looked the same as a normal array-index access; basically some magic parser rule that turned exists($foo['bar']) into array_key_exists($foo, 'bar') Looking at the generated opcodes, that could indeed be quite similar to how isset() works internally.
If such a function/syntax were built, I would argue that a plain exists($foo) should be a parse error, because there is no key to check, only a single value - it would be equivalent to array_key_exists($foo, null) or array_key_exists(null, $foo). For that reason, it should probably have a name that made its purpose clearer, too, but I'm not sure what that would be.
I admit this does partly come down to pre-judging any code that would use empty($foo) as "bad", but the warning issued when you access an uninitialised variable already makes such a judgement. And if people are already confused by the relationship between isset() is_null()
, empty(), etc, adding yet another variant is likely to hurt rather than help.
Regards,
Rowan Collins
[IMSoP]
If you've assigned meaning to that variable you should be initialising
it somewhere so that your code is more readable and less fragile.
+1
It would be nice to have variable declarations (such as var $foo or
TypeName $foo) and notices when using (especially assigning)
non-declared variables. They already did this for JavaScript...
--
Lauri Kenttä
It's also a "quirk" in the sense that suppressing that warning for a plain variable is an odd thing to want - if you've assigned meaning to that variable you should be initialising it somewhere so that your code is more readable and less fragile.
I don't think it is an odd thing to suppress a warning for a plain variable.
For example, on a blog you may have a list of articles, which is used by both the admin and users, but the (MVC) controller might set an $add_url, so a link to add a new article can be displayed...
Controller:
if (IS_ADMIN) {
$this->set('add_url', '/admin/articles/add/');
}
View:
<?php if (exists($add_url)) { ?>
<p><a href="<?= html($add_url) ?>">Add article</a>
<?php } ?>
Admittedly in this case the controller could be updated to something like the following:
$this->set('add_url', (IS_ADMIN ? '/admin/blog/add/' : NULL));
But it gets more complicated when you can have multiple things appearing (or not) on a page.
I admit this does partly come down to pre-judging any code that would use empty($foo) as "bad", but the warning issued when you access an uninitialised variable already makes such a judgement. And if people are already confused by the relationship between isset()
is_null()
, empty(), etc, adding yet another variant is likely to hurt rather than help.
I completely agree that we shouldn't be adding more functions lightly, and it's why I'm still not completely sold on the idea myself.
I think the main two negatives is adding yet another function (confusion), and that it will take a long time before developers can use it everywhere.
But, the thing that wins it over for me is that isset() seems to be (mis)used by a lot of developers as a function to check if the variable exists (not that the variable has a value).
So if implemented, in a few years (decades?), I suspect the exists() function would be the first function that comes to mind, instead of array_key_exists()
and isset().
Actually, in a few years time, if developers did their NULL
checks with "=== NULL", then isset(), is_null()
, array_key_exists()
, and empty() could all be deprecated :-)
Craig
But then again, I don't think it's a quirk that "you don't get a
warning when passing a completely undefined variable to isset()", as I
don't see isset() as a normal function.What I meant is that people seem to interpret isset() as having a special case for null values, and want that special case to go away. I was suggesting you could instead see it as a version of is_null with a special case to stop it complaining about non-existent variables. This makes sense, since in practice a "non-existent" variable (note: not array item or property) always has the value "null".
It's also a "quirk" in the sense that suppressing that warning for a plain variable is an odd thing to want - if you've assigned meaning to that variable you should be initialising it somewhere so that your code is more readable and less fragile.
With the
exists($foo['bar']['baz'])
example, I just see that as a
simple: if $foo exists, and contains the key 'bar', and contains the
key 'baz' (no need to check values).Like isset() I see exists() as a special function that isn't passing a
variable in, but PHP doing some analysis of the thing in the brackets.OK, thinking about it some more, I can see it would be convenient to have a special syntax for
array_key_exists()
which looked the same as a normal array-index access; basically some magic parser rule that turned exists($foo['bar']) into array_key_exists($foo, 'bar') Looking at the generated opcodes, that could indeed be quite similar to how isset() works internally.If such a function/syntax were built, I would argue that a plain exists($foo) should be a parse error, because there is no key to check, only a single value - it would be equivalent to array_key_exists($foo, null) or array_key_exists(null, $foo). For that reason, it should probably have a name that made its purpose clearer, too, but I'm not sure what that would be.
I admit this does partly come down to pre-judging any code that would use empty($foo) as "bad", but the warning issued when you access an uninitialised variable already makes such a judgement. And if people are already confused by the relationship between isset()
is_null()
, empty(), etc, adding yet another variant is likely to hurt rather than help.Regards,
Rowan Collins
[IMSoP]
Craig Francis wrote on 09/09/2015 16:54:
I don't think it is an odd thing to suppress a warning for a plain variable.
For example, on a blog you may have a list of articles, which is used by both the admin and users, but the (MVC) controller might set an $add_url, so a link to add a new article can be displayed...
Controller:
if (IS_ADMIN) {
$this->set('add_url', '/admin/articles/add/');
}View:
<?php if (exists($add_url)) { ?>
<p><a href="<?= html($add_url) ?>">Add article</a>
<?php } ?>
I can see that this makes nice terse View code, and is a reasonable use
of existing isset() - though I can't see it needs to be anything other
than isset(), because if $add_url was null, you wouldn't want to echo
anything.
Arguably, it would be better handled with the vars placed into an array
rather than materialising as PHP variables. The helper functions defined
by the framework (here assumed to be called exists() and html()) could
then extract items from that array, making it just as succinct:
<?php if (exists('add_url')) { ?>
<p><a href="<?= html('add_url') ?>">Add article</a>
<?php } ?>
Boom, no more worries about undefined variables.
I'm pretty sure this is how templating languages like Smarty and Twig
work - "{$foo}" in Smarty compiles to something like "echo
$this->vars['foo'];"
Presumably under the hood, the set() method in your example has to
instead do some magic with variable variables - $$foo syntax - which is
like the ugly cousin of an associative array. Either that, or eval(),
which as everyone knows is evil()! :P
But, the thing that wins it over for me is that isset() seems to be (mis)used by a lot of developers as a function to check if the variable exists (not that the variable has a value).
Do you mean that it is misused with arrays? Because with plain variables
it does exactly what it needs to do.
Or do you mean that developers are using unset() to represent a state
distinct from null? Because if so, that is their mistake, not the
subsequent use of isset(). I have yet to see a single use case where
distinguishing between these two states is necessary or sensible.
Actually, in a few years time, if developers did their
NULL
checks with "=== NULL", then isset(),is_null()
,array_key_exists()
, and empty() could all be deprecated :-)
-
is_null()
makes sense because it's a type-checking function: it goes
withis_bool()
,is_int()
, etc. - empty() is a bit odd because it's basically an inverted boolean cast,
but does make quite readable code. - You've just demonstrated yourself a situation where isset() can't be
replaced with === null oris_null()
because you want to suppress the
Notice. - I am fundamentally opposed to a function which distinguishes between
unset($foo) and $foo=null for reasons I have stated several times.
So the only thing left is replacing array_key_exists with some nicer
syntax so you can write some_keyword($foo['bar']) rather than
array_key_exists('bar', $foo)
Regards,
Rowan Collins
[IMSoP]
Craig Francis wrote on 09/09/2015 16:54:
I don't think it is an odd thing to suppress a warning for a plain variable.
For example, on a blog you may have a list of articles, which is used by both the admin and users, but the (MVC) controller might set an $add_url, so a link to add a new article can be displayed...
Controller:
if (IS_ADMIN) {
$this->set('add_url', '/admin/articles/add/');
}View:
<?php if (exists($add_url)) { ?>
<p><a href="<?= html($add_url) ?>">Add article</a>
<?php } ?>I can see that this makes nice terse View code, and is a reasonable use of existing isset() - though I can't see it needs to be anything other than isset(), because if $add_url was null, you wouldn't want to echo anything.
Arguably, it would be better handled with the vars placed into an array rather than materialising as PHP variables. The helper functions defined by the framework (here assumed to be called exists() and html()) could then extract items from that array, making it just as succinct:
<?php if (exists('add_url')) { ?>
<p><a href="<?= html('add_url') ?>">Add article</a>
<?php } ?>Boom, no more worries about undefined variables.
It depends, the exists() was simply to show the proposed function in place, and html() was more to show a cut down version of htmlentitites.
Most frameworks I've used typically have plain variables in the View (templating engines are a bit different)... but I have used a $v[] array on my own project before (many years ago), but it got quite ugly... especially when it's often passing multi-dimentional arrays (or objects) into the View.
So yes, in the example above, an isset() would work, but I was trying to show why I don't think it's odd to "suppress a warning for a plain variable" when it does not exist.
I'm pretty sure this is how templating languages like Smarty and Twig work - "{$foo}" in Smarty compiles to something like "echo $this->vars['foo'];"
Presumably under the hood, the set() method in your example has to instead do some magic with variable variables - $$foo syntax - which is like the ugly cousin of an associative array. Either that, or eval(), which as everyone knows is evil()! :P
Actually, I think they do use an array to store the values, then do an extract()
to make them local variables in the View (keeping the variable names shorter and easier to read).
The code I'm looking at today uses a function to include the View, such as:
function script_run() {
if (func_num_args() > 1) {
extract(func_get_arg(1));
}
require(func_get_arg(0));
}
script_run($view_path, $variables);
But, the thing that wins it over for me is that isset() seems to be (mis)used by a lot of developers as a function to check if the variable exists (not that the variable has a value).
Do you mean that it is misused with arrays? Because with plain variables it does exactly what it needs to do.
Or do you mean that developers are using unset() to represent a state distinct from null? Because if so, that is their mistake, not the subsequent use of isset(). I have yet to see a single use case where distinguishing between these two states is necessary or sensible.
Yes, it is mis-used with arrays, but I would still argue that a single exists() function would work better for all of these examples when testing if they exist.
And I would hope that no-one was using an unset() as something distinctly different from a NULL
value.
Actually, in a few years time, if developers did their
NULL
checks with "=== NULL", then isset(),is_null()
,array_key_exists()
, and empty() could all be deprecated :-)
is_null()
makes sense because it's a type-checking function: it goes withis_bool()
,is_int()
, etc.- empty() is a bit odd because it's basically an inverted boolean cast, but does make quite readable code.
- You've just demonstrated yourself a situation where isset() can't be replaced with === null or
is_null()
because you want to suppress the Notice.- I am fundamentally opposed to a function which distinguishes between unset($foo) and $foo=null for reasons I have stated several times.
So the only thing left is replacing array_key_exists with some nicer syntax so you can write some_keyword($foo['bar']) rather than array_key_exists('bar', $foo)
I agree that we should not have a function that distinguishes between unset($foo) and $foo=null.
But I believe the isset() function is often used just to see if the variable exists (i.e. avoiding the undefined variable notice), and having the extra "and is not NULL" logic does not help in this situation.
It's just the "and is not NULL" logic causing problems when the developer should be using array_key_exists.
So if we look at it from the point of view of "lets kill isset" (just humour me for a second)...
The proposed exists() function should be the go to function, and used to avoid undefined variable notices (e.g. the View variables).
Then to check if the variable is NULL, just do a "=== NULL", which is much better because it will complain if the variable is undefined (or you get your wish, and isset() could be updated to raise a notice for undefined variables).
Anyway, I'm off on holiday tomorrow, so I doubt I will be able to follow up for a couple of weeks.
Craig
Craig Francis wrote on 14/09/2015 12:46:
So yes, in the example above, an isset() would work, but I was trying to show why I don't think it's odd to "suppress a warning for a plain variable" when it does not exist.
Yes, and I agree that this example shows a reasonable use of isset(). It
works fine as it is, and doesn't need any functionality adding or removing.
Actually, I think they do use an array to store the values, then do an
extract()
to make them local variables in the View (keeping the variable names shorter and easier to read).
Incidentally, I've always wondered why extract()
would ever be useful in
modern code, but I agree that if you don't want/need the overhead of a
separate template compiler, that approach actually works quite nicely.
Yes, it is mis-used with arrays, but I would still argue that a single exists() function would work better for all of these examples when testing if they exist.
And I would hope that no-one was using an unset() as something distinctly different from a
NULL
value.
If you don't need the ability to distinguish unset() from null, what
would any of these examples gain from using exists() over isset()?
I agree that we should not have a function that distinguishes between unset($foo) and $foo=null.
But if you take the "is null" check out of isset(), that's exactly what
you have; that's why the "is null" check is there in the first place.
That's why I said I could agree with an exists() function (not under
that name) as a nicer syntax for array_key_exists()
, but not as a
replacement for isset().
You could have an exists() function which works like array_key_exists()
on an array, but identically to isset() on plain variables, but I think
that would just be confusing. Hence my suggestion that any new function
throw an error if given something other than an array access.
Regards,
Rowan Collins
[IMSoP]
Hi Rowan,
I think I've said everything I can from my point of view (and my understanding of how other developers see and use the isset function).
And that's not to say I disagree with what your saying Rowan, I'm just voicing my view that I think a language with exists() would be nicer than the slightly messy isset()... but each to their own.
Maybe Scott (who proposed the idea) might follow up with more information?
Otherwise I'm off on holiday, see you in a few weeks :-)
Craig
Craig Francis wrote on 14/09/2015 12:46:
So yes, in the example above, an isset() would work, but I was trying to show why I don't think it's odd to "suppress a warning for a plain variable" when it does not exist.
Yes, and I agree that this example shows a reasonable use of isset(). It works fine as it is, and doesn't need any functionality adding or removing.
Actually, I think they do use an array to store the values, then do an
extract()
to make them local variables in the View (keeping the variable names shorter and easier to read).Incidentally, I've always wondered why
extract()
would ever be useful in modern code, but I agree that if you don't want/need the overhead of a separate template compiler, that approach actually works quite nicely.Yes, it is mis-used with arrays, but I would still argue that a single exists() function would work better for all of these examples when testing if they exist.
And I would hope that no-one was using an unset() as something distinctly different from a
NULL
value.If you don't need the ability to distinguish unset() from null, what would any of these examples gain from using exists() over isset()?
I agree that we should not have a function that distinguishes between unset($foo) and $foo=null.
But if you take the "is null" check out of isset(), that's exactly what you have; that's why the "is null" check is there in the first place.
That's why I said I could agree with an exists() function (not under that name) as a nicer syntax for
array_key_exists()
, but not as a replacement for isset().You could have an exists() function which works like
array_key_exists()
on an array, but identically to isset() on plain variables, but I think that would just be confusing. Hence my suggestion that any new function throw an error if given something other than an array access.Regards,
Rowan Collins
[IMSoP]
Craig Francis wrote on 14/09/2015 16:57:
Hi Rowan,
I think I've said everything I can from my point of view (and my understanding of how other developers see and use the isset function).
And that's not to say I disagree with what your saying Rowan, I'm just voicing my view that I think a language with exists() would be nicer than the slightly messy isset()... but each to their own.
Maybe Scott (who proposed the idea) might follow up with more information?
Otherwise I'm off on holiday, see you in a few weeks :-)
Yes, I think we're going round in circles at this point, and should see
if anyone else has an opinion that would move the discussion forward.
Have a nice holiday! :)
Regards,
Rowan Collins
[IMSoP]
I really don’t understand the resistance to this type of change, other than knowing that a fix will necessarily be messy. The fact is, PHP distinguishes between a variable that has been declared but defined to null and one that hasn’t been declared. The value of the first may safely be assigned, compared, referenced, and so on, while attempting any of those things on the second one results in an error message. The question of whether relying on those differences is philosophically acceptable is a moot point: they are different, period, and the rest of the language should acknowledge and support that — just as do most other languages with a similar design (e.g., JavaScript).
Beyond that, the philosophical debate is clearly settled in the real world of code. One glance through the comments on the isset() documentation page, not to mention the bug reports and the discussions on the lists, shows that people have long struggled with this. Based on code I’ve seen from fairly experienced developers, the confusion around this has probably led to millions of production bugs, many of them in the areas of validation and security. When a particular aspect of a language's design promotes bugs to such an extent, it needs to be revisited.
I’m not sure what a good solution is, however. Changing isset() will have consequences: making it return true for null will magically fix a lot of bugs out there, but it’ll also break code where the programmer understood how it really works. Adding a parameter to control it is ugly. Extending defined()
to variables might be a good choice, as it’s already doing for constants exactly what’s needed for variables; the only downside is that it would be better-named declared() than defined()
, but that’s the case for constants, too, so I can live with it. For now, isset() and empty() can continue to work as-is but perhaps with a notice and deprecation when used with undeclared variables.
--
Bob W.
Hi!
Just because there is a function, which does not exactly roll off the
tongue (plus the fun of the needle/haystack ordering issue), does not
mean it gets used (even if it is the correct thing to use).
As it looks to me, in order to fix the fact that people are
not using existing function (which completely satisfies the
requirements), because people do not read the docs, the proposal is to
create another function (which nobody knows about without reading the
docs) that does the same? If so, I'm not sure how that is supposed to
help anything.
--
Stas Malyshev
smalyshev@gmail.com
Just because there is a function, which does not exactly roll off the
tongue (plus the fun of the needle/haystack ordering issue), does not
mean it gets used (even if it is the correct thing to use).
As it looks to me, in order to fix the fact that people are
not using existing function (which completely satisfies the
requirements), because people do not read the docs, the proposal is to
create another function (which nobody knows about without reading the
docs) that does the same? If so, I'm not sure how that is supposed to
help anything.
We have had discussions before over the various 'complaint' sites and
how in many cases the 'complaints' get more prominence than the actual
current 'solution'. Yet again, what is needed rather than a manual
describing each function individually since for example one would not
look under 'array_' for a solution to this problem, is a 'best practice'
example which can help even those of us who are stuck with legacy
practices which COULD be improved with better modern samples.
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Hi!
Depending on the website I may then add a key to define the
'report-uri', or I may set it toNULL
to say that I don't want one.
NULL
is not the best value to for this, but the function you're looking
for is array_key_exists()
.
--
Stas Malyshev
smalyshev@gmail.com
Depending on the website I may then add a key to define the
'report-uri', or I may set it toNULL
to say that I don't want one.
NULL
is not the best value to for this, but the function you're looking
for isarray_key_exists()
.
What would be the best value?
And the array_key_exists()
function has already been mentioned (and is what I'm using... but I cut that bit out to keep the reply shorter, as mentioned in my previous email).
On Wed, Aug 26, 2015 at 11:08 AM, Craig Francis craig@craigfrancis.co.uk
wrote:
Depending on the website I may then add a key to define the
'report-uri', or I may set it toNULL
to say that I don't want one.
NULL
is not the best value to for this, but the function you're looking
for isarray_key_exists()
.What would be the best value?
And the
array_key_exists()
function has already been mentioned (and is
what I'm using... but I cut that bit out to keep the reply shorter, as
mentioned in my previous email).
What I would do is use false to me I don't want this, and null/not set to
mean do the default, and a value to mean this is what I want. Then you end
up with:
if (!isset($val)) {
// do the default
} elseif (!empty($val)) {
// do something with $val
}
// else do nothing because I don't want this thing
On the other hand, if I'm designing something using null as a special case
value, then I would just use array_key_exists and is_null (these calls
exist a few times in my code) but generally speaking I try not to give null
special meaning.
Scott Arciszewski wrote on 26/08/2015 04:09:
Hi everybody,
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?
My answer to this would be a very loud "no".
I have written at length about this on StackOverflow:
http://stackoverflow.com/a/18646568/157957
In short, if your algorithm relies on knowing whether, anywhere in the
preceding scope, a variable has been implicitly "declared" (in as much
as that concept has any meaning in PHP), that algorithm is broken. If it
relies on knowing whether a variable has been changed from its initial
state, then isset() will do exactly what you want.
Note that many people looking for examples of this "problem" start
mentioning array keys and object properties; we have functions for
checking existence of those, so please don't waste time on such examples.
Regards,
Rowan Collins
[IMSoP]
On Tue, Aug 25, 2015 at 11:09 PM, Scott Arciszewski scott@paragonie.com
wrote:
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?
Agree with Rowan as he mentioned here:
http://stackoverflow.com/a/18646568/2908724
Perhaps this idiom will solve your use case?
array_key_exists('x', compact('x')));
Cheers,
bishop
Bumping in (senior dev here).
I think this function must be implemented.
Every dev I've seen in my company use isset() as its name says it does :
"Is this variable set, whatever its value is ?". That's exactly how we use
it in the code. And we use "null" a lot too. For us, "null" is a value
like another. The irony is, we set a variable to "null" mostly to avoid
"Undefined variable" notices. To explain it shortly, when we see "$var =
null;", we know that it is a variable that could not be changed in the
scope.
It is logical (at least for us) that "isset()" returns true when a
variable exists, even if its value is "null". I've yet to discover a
security bug in our code, but we have very sensitive applications, in
which we widely use "isset()". It could cause a lot of damages (maybe it
already has, but haven't noticed yet), and "exists()" would prevent them.
Since we have "array_key_exists()", which is basically "exists()" for an
array element, I don't see why "exists()" shouldn't be implemented. I
don't see the logic here.
"isset()" and "empty()" wouldn't change, there couldn't any BC. Excepted
for the userland code, in which there would already be an "exists()"
function.
Regards,
Le Wed, 26 Aug 2015 05:09:43 +0200, Scott Arciszewski
scott@paragonie.com a écrit:
Hi everybody,
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it off
until 7.1.Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises https://paragonie.com
--
Utilisant le logiciel de courrier d'Opera : http://www.opera.com/mail/
Benoit Schildknecht wrote on 15/09/2015 18:04:
Every dev I've seen in my company use isset() as its name says it does
: "Is this variable set, whatever its value is ?". That's exactly how
we use it in the code.
Can you give an example of code where you do not know this until the
code runs - i.e. where "is this variable set?" is something you can hang
business logic on?
Somewhere where it would make sense to write something like this, if the
exists() function were available for plain variables:
if ( exists($a) ) {
...
} elseif ( is_null($a) ) {
...
} else {
...
}
The irony is, we set a variable to "null" mostly to avoid "Undefined
variable" notices. To explain it shortly, when we see "$var = null;",
we know that it is a variable that could not be changed in the scope.
Why is that ironic? That's exactly what the notice is telling you to do
- assign an explicit value to your variables to say "this variable
intentionally left blank".
It is logical (at least for us) that "isset()" returns true when a
variable exists, even if its value is "null". I've yet to discover a
security bug in our code, but we have very sensitive applications, in
which we widely use "isset()". It could cause a lot of damages (maybe
it already has, but haven't noticed yet), and "exists()" would prevent
them.
Again, I challenge you - or anyone - to give a single, theoretical,
example of such a bug. The only ones I can think of are made worse by
use of exists(), not better, because they allow programmers to write
extremely brittle code, as in the example I posted earlier of
refactoring to extract code into a new function:
...
unset($foo);
refactored_code($foo);
...
function refactored_code($bar)
{
if exists($bar) // oops, this is always true
...
}
This is why I'm so opposed to the suggestion, because not only can
people use it to write really bad code, I've yet to see an example where
it would lead to good code. If we're interested in the reputation of the
language, adding facilities for doing things badly doesn't sound like a
good move.
Regards,
Rowan Collins
[IMSoP]
Can you give an example of code where you do not know this until the code runs - i.e. where "is this variable set?" is something you can hang business logic on?
Somewhere where it would make sense to write something like this, if the exists() function were available for plain variables:
if ( exists($a) ) {
...
} elseif ( is_null($a) ) {
...
} else {
...
}
Sure. It’s not common with controlling business logic (fortunately), but it is very common in error-handling code. I already mentioned the templates, but an even more common scenario is config files that are supposed to just define a bunch of standalone variables, which is a very common pattern. If you’re writing code that relies on those variables, or you’re writing the code that’s supposed to pull that file in to begin with, it’s smart to make sure all the variables actually got set, and if not, display an error to the user to go fix the config. Sometimes, isset() works for this if combined with a null check, but it fails in cases where null is an acceptable value.
-Bob
Robert Williams wrote on 16/09/2015 18:27:
an even more common scenario is config files that are supposed to just
define a bunch of standalone variables, which is a very common
pattern. If you’re writing code that relies on those variables, or
you’re writing the code that’s supposed to pull that file in to begin
with, it’s smart to make sure all the variables actually got set, and
if not, display an error to the user to go fix the config. Sometimes,
isset() works for this if combined with a null check, but it fails in
cases where null is an acceptable value.
OK, that's a reasonable example, though I'd say it's still very much an
edge case. It requires the following to all be true:
- the config file defines bare variables rather than array or object keys
- the variable in question has null as a valid value
- the variable in question is mandatory, with no default value
I will admit that exists($foo) would be useful in that situation, but it
doesn't feel to me like such a common or useful scenario that it
justifies the language changing to suit that design, rather than the
design changing to suit the language.
Regards,
Rowan Collins
Hi everybody,
Would anyone be interested in adding another helper like
isset()/empty() simply called exists() which would return true if the
variable is defined in the current scope (i.e. without raising an
E_NOTICE)?It should be a simple change to add this function but it's too late
for 7.0 so, if there is any interest, I would respectfully put it off
until 7.1.
After reading through this thread (most of it anyway), the thing that
strikes me is that many people expect the wrong thing from isset(). I
believe that the reason for this is that the name isset() is slightly
misleading. I wouldn't blame anyone for assuming that it acually
checks that a variable "is set", and not even considering the corner
case of when it does exist with a null value.
What lesson can we learn from that? Short and sweet names sometimes
lead to problems, if they do not precisely convey the actual
semantics.
I would much rather see a function called something like
is_variable_defined(), to avoid running into the same trap with
exists(). No room for assumptions that lead you to not check the docs.
- Stig
Stig Bakken wrote on 18/09/2015 14:44:
What lesson can we learn from that? Short and sweet names sometimes
lead to problems, if they do not precisely convey the actual
semantics.I would much rather see a function called something like
is_variable_defined(), to avoid running into the same trap with
exists(). No room for assumptions that lead you to not check the docs.
I agree 100% with this. If we do add a new function, which I'm still
not entirely convinced of the need for, we should be very explicit about
what it does, and very careful in naming it.
Regards,
Rowan Collins
[IMSoP]