Terminology question on "dereferencing"? - php

In PHP, the following code is valid
$a=array(0);$a[0];
but that one is invalid:
array(0)[0]
What is the terminology corresponding to that behaviour? (has it anything to do with "dereferencing"?)
What is the motivation behind such a behaviour (besides user spite :-P)
I am looking for the general terminology, not necessarily the terminology associated with PHP.
(Other example: in MATLAB, the following is valid:
s = size(M)
s(0)
but that is invalid:
size(M)(0)
In both PHP and MATLAB, adding parenthesis does not help, i.e., (array(0))[0] and (size(M))(0) are both invalid)

That's called Array dereferencing, and will become available in PHP 5.4 (which is currently in alpha)
Note (thanks Gordon) : what you are asking for, with array()1, is not possible even in PHP 5.4 -- but it'll work for functions.
A couple of sources :
RFC - Function Array Dereferencing
Features in PHP trunk: Array dereferencing, when it was unsure whether there would be a PHP 5.4 or a PHP 6
And, last but not least, the (currently last) news on php.net : PHP 5.4 alpha1 released
Quoting that last news :
Here is an incomplete list of changes: - Added: Traits language
construct - Added: Array dereferencing support - Added:
DTrace support - Improved: Improved Zend Engine memory usage and
performance - Moved: ext/sqlite moved to pecl (sqlite3 support is
still built-in)
1.array() is not a function, even if it looks like one -- it's actually what PHP calls a language construct ; and those don't behave like functions.

This is called "array dereferencing" and it will be available for use in PHP5.4.

Related

How would I handle a fatal error while setting up Calendar API on PHP

Following the Google Calendar API quickstart for PHP, I've followed the steps but, got the verification code and instead of getting the expected output " No upcoming events found " I get a
No idea how to move forward from here...
Welcome to StackOverflow!
I've encountered this very same error with numerous WP plugins that had been developed before PHP 5.6 and where programmers have been, well, lazy. Once these plugins get upgraded to PHP 7, exceptions are thrown for things that were mere deprecation warnings a few years ago.
From what I see in your logs, you have a dependency somewhere on Guzzle. According to Guzzle's own documentation, the recent versions require PHP 7.2.5 to work. Therefore, I can only assume that you are:
using a plugin or something similar that is based on an outdated version of Guzzle or you're using Guzzle yourself, but for some reason relying on a deprecated version of it (in the former case, you'd have to pester the plugin developer to update their own dependencies...);
using PHP 7.2 or perhaps even a later version.
You should be using PHP 7.4 or 8.0 as of mid-2021 (everything else has been deprecated), so your installation is fine. It's just the obsolete code coming from that outdated version of Guzzle that requires updating.
So, a simple fix for that issue is to look at the culprit — open on your favourite editor the file C:\xampp\htdocs\api\vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php and scroll down to line 67 (where the exception was thrown).
According to the trace you've posted, on that line you should have something like:
if (count($some_variable_name_here) [...]) { [...] }
What happened, in this case, was the following:
The count() function requires what PHP calls a Countable object. Generally speaking, historically, these were arrays of some sort.
Lazy programmers often use count() simply to check if the array is empty or not. In the pre-PHP7 days, count(NULL) was defined as being 0 or false, like so many other things in PHP. In other words: if the array was either empty (i.e. initialised but still without any item stored inside) or uninitialised (i.e. still assigned to NULL) or non-existent (i.e. a new variable which had not been declared before), then, by definition, count(NULL) was false.
This allowed lazy programmers to check for a handful of potentially different error conditions with a single if (!count($myArray)) { [...] do this; }. In other words, you would just execute that code inside brackets if $myArray existed, was correctly initialised, and had at least one valid element. All that with a 'simple' check!
Unfortunately, from the perspective of the interpreter and JIT compiler, as well as many other modern optimisation tools used by recent versions of PHP, this is terribly inefficient — besides being very sloppy programming. Starting with PHP 5.6, this misuse of count() became flagged as a warning, then later shown as a deprecated, and finally started throwing exceptions.
So, in your case, whatever is on line 67, count($some_variable_name_here) has been passed an empty/invalid variable/array/object, and while this would be fine before PHP 7, it now throws an exception: count() will not work with so-called 'uncountable' objects, and for all purposes, an unexisting/empty/invalid object is uncountable by definition.
To fix it, all you need to do is to check first if the object is valid and not null, and then you can check if it has any elements inside it. In other words, instead of having something like:
if (count($some_variable_name_here) [...]) {
[... do something ...]
}
change it to:
if (!empty($some_variable_name_here) && is_countable($some_variable_name_here) && count($some_variable_name_here) [...]) {
[... do something ...]
}
Note that empty() is a shortcut for !isset($var) || $var == false, and that PHP evaluates expressions from left to right, aborting as soon as a final result is known. If the variable is empty, the first check will immediately return true and the remaining checks will not even be called; by design, empty() does not throw an error or an exception and is safe to use in all scenarios where variables are in an 'unknown' state.
In many cases, you might get away just by checking if the object $some_variable_name_here is countable or not; a NULL object is not countable, so, it would also fail. In other cases — most frequent these days — you might not really know what has been passed: it might not be a valid, countable object. It might have more than one element, or zero. It might be just garbage and not properly initialised. Or any other possible combination. In those cases, being extra-careful with the checks (as opposed to being sloppy and relying upon PHP to do something useful with an otherwise useless variable/array/object) pays off.
Anyway, I've checked, and the current version of Guzzle's CurlFactory.php still has a count() for function release(), which is what is called before the exception is thrown. However, your own code is clearly different (at the time of writing, the current version has the count() on line 80, not 67), so it's very hard to say if you can correct it easily (there might be other, more subtle errors in the code calling release()...).
One assumes that Guzzle's latest version will fix these and other issues you might have — mostly because they demand PHP 7.2.5 or later, and that means that they have made changes to fix earlier things that didn't work as they should, and such changes were only possible with PHP 7.2.5.
Thus the recommendation is to upgrade your version of Guzzle. If there is any good reason to keep an outdated (and potentially bug-ridden and security-flawed) version around, well, now you know how to do a simple fix. At the very least, your code won't throw an exception; with luck, it will even work as you expect...
Happy hunting!

PHP Syntax, is $this->(stuff) ->(more stuff) the same as $this->(stuff); $this->(more stuff)?

just learning PHP and I have a project I'm looking at which appears to have typos but I'm not sure if they are or not.
I want to know if the output of the two bits of code below is the same.
$this->addSubmitElement($this->_buttons[self::BTN_LIST], self::BTN_LIST);
$this->addSubmitElement($this->_buttons[self::BTN_DRAFT], self::BTN_DRAFT);
and
$this->addSubmitElement($this->_buttons[self::BTN_LIST], self::BTN_LIST)
->addSubmitElement($this->_buttons[self::BTN_DRAFT], self::BTN_DRAFT);
It seems it should be but my project behaves differently depending on which version I have.
There's a common pattern used when designing 'mutating' methods (setSmth, addSmth) that update some properties of an object: use that object (i.e., $this) as return value.
Following this pattern enables chaining you've showed in your second example. Note that this is a pattern, but not a requirement; if the package changed, you're not able to use that approach anymore.

check the php version compatibility of a php script

I have a php script. I want to check the php version compatibility that each function of this script has.
For example the script has the hash() function. If we look at php.net site it says that this function was added (PHP 5 >= 5.1.2, PECL hash >= 1.1).
So assuming that this script has only this function we say that it is compatible with php 5.1.2 and onwards. Is there any software tool that can scan the script and tell you the changelog of every function and possibly gives you the lowest possible score e.g. (php version 4.3 and on)? It is a bit tedious to check manually every function in the script.
Thank you in advance
As PHP supports dynamic function/method names, just searching through the source code would not give reliable results.
Example:
$function = 'strpos';
$result = $function(...);
You might use xdebug function traces together with a 100% test coverage. This could give you all function names which had been called during a test suite run with 100% coverage - meaning all code has run. But even this isn't reliable as you would have to make sure, that your test suite covered all possible dynamic function names what is impossible. (assuming the max length of a function name is unlimited)
My final answer is: this isn't reliably possible.

PHP ignoring returned reference from function considered harmful?

Derick Rethans has an old article that says:
Please do note that it is harmful not to accept a reference from a
function that returns a reference. In some cases, PHP will get
confused and cause memory corruptions which are very hard to find and
debug. It is also not a good idea to return a static value as
reference, as the PHP engine has problems with that too. In PHP 4.3,
both cases can lead to very hard to reproduce bugs and crashes of PHP
and the web server. In PHP 5, this works all a little bit better. Here
you can expect a warning and it will behave “properly”.
Does it mean that in PHP 5 we are allowed to ignore the returned reference from a function?
By that, I mean this:
function &GetRef(&$array){
$item =& $array[0];
return $item;
}
$array = array(0, 1, 2);
$item =& GetRef($array); /* Normal usage of the function using assign by reference
also known as "accepting" the reference. */
$item = GetRef($array); /* Notice that here we didn't assign by reference.
Are we allowed to ignore the returned reference
and simply do normal assignment? */
The PHP Manual states:
Unlike parameter passing, here [return by reference] you have to use &
in both places - to indicate that you want to return by reference, not
a copy, and to indicate that reference binding, rather than usual
assignment, should be done for $myValue.
It doesn't explicitly say that we must accept the returned reference.
Does it mean that we are free to ignore returned references?
As discussed in the comments, you should generally ignore at least that section in the linked article, if not the entire thing.
The article talks about references in the context of PHP 4.3, released in December, 2002 and EOL'd at the end of 2007. PHP 4 should never be used today. As a general rule, when it comes to learning about working with PHP, you should not trust any article that targets PHP versions older than 5.2 (as of mid-2013).
PHP 5.0 features Zend Engine 2, a new virtual machine on which PHP runs. This is where references are implemented. 5.1 introduces some backwards-incompatible changes with regard to manipulation of return values. 5.3 introduces real garbage collection and deprecates both call-time pass-by-reference and assigning new by reference. These important changes are not addressed by that prehistoric article.
Does it mean that in PHP 5 we are allowed to ignore the returned reference from a function?
Yes. Modern PHP versions have no problem with discarding the return value of any function, reference or not. If you encounter behavior that seems to contradict this expectation, create a reduced test case and file a bug with the PHP maintainers.
Also, think twice before using references in your code. Passing around references will not save time, will not save memory and will not increase performance except in rare cases. Use them sparingly to keep complexity under control.

PHP 5.2 permitted object syntax to call array index?

We recently had a disaster and had to move our php web application from PHP Version 5.2.6-1+lenny16 to PHP Version 5.3.3-7+squeeze15 and found a seemingly important difference.
In our application, there were instances where we incorrectly called an array's index using object syntax:
echo $array->index;
However, 5.2.6 seemed to forgive this, and correctly treat it as if $array['index'] was written.
Upon further testing, what 5.2.6 is specifically doing is disagreeing with 5.3.3 as to whether $array->index is empty();
Here is the test code I've run on both servers:
<?php
echo phpversion() . '<br>';
$array = array(
'x' => 1,
'y' => 2
);
if (!empty($array->x))
{
echo "not empty";
}
else
{
echo "empty";
}
?>
Here are the two different outputs:
5.2.6-1+lenny16
not empty
5.3.3-7+squeeze15
empty
Naturally, there are now a few outbreaks of broken functionality because we were never alerted to these errors during development. Is there a way we can configure php 5.3 to permit this incorrect syntax while we take a bit more time to find all the incorrect instances of it?
I don't think it's a configuration issue, is it? Was something changed in the way empty() works in between versions?
I just have put your example code to a general test across PHP versions (test) and it shows that you are correct, there are differences:
From PHP 5.0.0 up to 5.2.11 (and also early 5.3.0 to 5.3.1), this "undefined property" was reported as not empty which does qualify as a flaw or bug.
The related change in 5.2.12 (17 Dec 2009) was (ref):
Fixed bug #50255 (isset() and empty() silently casts array to object). (Felipe)
Technically this is not a backwards incompatible change from PHP 5.2 to 5.3 because it was a flaw in both branches and also fixed in both. Those are harder to spot if you migrate, because the standard migration guide does not cover them. Instead you need to go through the changes of the software and look for notes and references to tickets.
So to answer your question: This is a configuration issue because the PHP version used counts as configuration. You changed the configuration and then you had the issue.
Also as the report shows, this is limited to empty() and isset(), not general object/array access. As you can imagine, if that would have been the case, you would have found much more reference about it.

Categories