|
Posted by Rasmus Lerdorf on 09/16/05 17:28
Stephen Leaf wrote:
>
> $this->urlArr[0] = array_pop($arr = explode("&",$this->urlArr[0]));
>
> I still have to scratch my head as to why I *need* that "$arr = "
> prior to 5.0.5 this was not needed.
> $this->urlArr[0] = array_pop(explode("&",$this->urlArr[0]));
This is a much misunderstood issue. And we are still contemplating the
best way to handle this. Let's take a step back to a really simple example:
function foo() {
return 3;
}
function bar(&$arg) {
$arg = "banana";
}
bar(foo());
What do we do with code like this? If you follow it through it is
essentially doing:
3 = "banana";
which makes very little sense and is probably something the developer
would want to know about. PHP 4.3.x happily let you do this, and in
some circumstances this could even corrupt memory. PHP 4.4 and higher
have fixed this memory corruption problem, and at the same time since we
are now able to detect this we can throw an error to let you know that
your code is probably not doing what you intended.
Now, in your example you are doing:
$a = array_pop(explode("&","a&b"));
to get the last element from the explode. The issue with array_pop()
and other similar functions is that they do 2 things. They modify the
array (by removing the last element) and they return something (the
removed element in this case). When you pass in the result of explode()
you are passing in something that doesn't have any permanent storage
associated with it. Internally in PHP this is known as a temp var. You
can't make a reference to a temp var. In our simpler example it is like
trying to do &3 which doesn't make any sense. So in this case
array_pop() has no place to store the modification. Your code happens
to not care about that and only cares about the returned value.
The real question here is whether we should silently ignore cases where
such an argument modification is thrown away. In the case of
array_pop() it may make sense. But how about this:
sort(explode("&","a&b"));
sort() has just one purpose. That is to sort the passed array in place.
The above line of code is a really slow line of code that does
absolutely nothing because we are passing in something that goes out of
scope as soon as the call is done. This line of code in a PHP program
is an obvious bug. Now, if we change this to:
sort($a=explode("&","a&b"));
then it suddenly makes sense. This is equivalent to writing:
$a = explode("&","a&b"));
sort($a);
and the result is that we have a sorted array in $a after this.
So the idea here is that PHP should be able to detect these sorts of
obvious errors. In the array_pop() case it is not as black and white as
the sort() case because of the dual-purpose nature of array_pop(). You
could make a case for silently ignoring the array modification in
array_pop().
My personal feeling on this is that we should throw an E_NOTICE on these
and let the code continue on. Often there is a more efficient way to do
some of these things simply because you are calling something that does
more than you need and ignoring some of what the function does and other
times, like with the sort() example, this is actually a real bug in your
code.
If it wasn't for the memory corruption associated with this, we wouldn't
have touched it in PHP 4 at all. But since it caused weird and
wonderful crashes in complex PHP 4 code we didn't really have the option
to ignore it. So what we do now is to demote impossible references to
non-references and throw an E_NOTICE. In PHP 5 this ended up being a
fatal error which is something we have been discussing over the past
week. In its current state having this as a fatal error is incorrect
and something we will fix. We need to either make it an E_NOTICE or
there has been talk about coming up with a smarter way of handling these
impossible reference cases, but it is pretty tricky.
We don't always get things right on the first try. Expect to see some
tweaks to the current implementation to make it more compatible with
existing code over the next couple of weeks.
-Rasmus
[Back to original message]
|