I am trying to execute this code (it was working on php5, now I'am on php7):
$this->links->$data[$te]['attributes']['ID'] = $data[$te]['attributes']['URL'];
But I get this error:
ContextErrorException: Notice: Array to string conversion
Thanks in advance
This is down to the change in how complex variables are resolved in PHP 5 vs 7. See the section on Changes to variable handling here: http://php.net/manual/en/migration70.incompatible.php
The difference is that the expression:
$this->links->$data[$te]['attributes']['ID']
is evaluated like this in PHP 5:
$this->links->{$data[$te]['attributes']['ID']}
and like this in PHP 7:
($this->links->$data)[$te]['attributes']['ID']
See https://3v4l.org/gB0rQ for a cut-down example.
You'll need to amend your code to be explicit, either by using {} as appropriate, or by breaking it down into two lines. In this case, where you've got code that works fine in PHP 5, pick the former, since it will mean the behaviour stays consistent in all versions of PHP.
Related
This question already has answers here:
PHP Notice: Array to string conversion only on PHP 7
(2 answers)
Array to string conversion - Variable function name calling
(1 answer)
Closed 11 months ago.
[NOTE: I solved this problem in the course of drafting the
question, but figured I would proceed with posting it for future
reference, since my extensive searching on the warnings delivered did
not provide the solution and I figure this might help someone in the
future.]
I have a class Thing that has properties $subthing_1, $subthing_2, $subthing_3, all of which are objects:
class Thing {
...
public $subthing_1; // object of type Subthing
public $subthing_2; // object of type Subthing
public $subthing_3; // object of type Subthing
...
}
If I want to get a particular subthing in an instance of Thing, I can do:
$thing->subthing_1
and this works just fine to deliver that subthing. But I want to generalize which of the subthings are called, so I have a routine that gets the name of a particular subthing, either 'subthing_1', 'subthing_2', or 'subthing_3', and stores it in a string in an array element. Thus, $subthings[4] has string value 'subthing_1', for example, and
$thing->$subthings[4]
should deliver exactly the same as $thing->subthing_1.
If I do
var_dump($subthings[4]);
the result is
string(10) "subthing_1"
and for
var_dump($thing);
the result is
object(Thing)#4 (87) {
...
["subthing_1"]=>
object(Category)#59 (12) {
...
}
...
}
Which is all fine and good. However, when I try to do this:
var_dump($thing->$subthings[4]);
I get this:
Warning: Array to string conversion ...
Warning: Undefined property: Thing::$Array ...
Warning: Trying to access array offset on value of type null ...
This confused me for a long time, because I couldn't see where an array was being converted to a string. $subthings[4] is clearly a string, as indicated by var_dump($subthings[4]), not an array.
These warnings are appearing in PHP 8.1 for code that worked just fine in PHP 5.5.
Eventually I reasoned that there must have been a syntax interpretation change somewhere between these two PHP versions.
Whereas in PHP 5.5, $thing->$subthings[4] is interpreted as $thing->{$subthings[4]}, in PHP 8.1 $thing->$subthings[4] is interpreted as {$thing->$subthings}[4].
I have searched high and low for documentation of this change, but I guess I am not hitting on the right keywords. I hope someone here can supply an answer for where this change is documented.
The SOLUTION is to surround the arrays with curly braces to enforce the expected (and formerly default) parse ordering:
$thing->{$subthings[4]}
As pointed out by Don't Panic, this evaluation syntax change is documented here:
https://www.php.net/manual/en/migration70.incompatible.php#migration70.incompatible.variable-handling.indirect
Before anyone mark my question as duplicate, I wish to clarify that my case is unique and specific to PHP 7 (I use PHP 7.1.1 in UniformServer). I have seen all other similar questions here and they did not work for me.
I had a working code as below:
In class constructor:
$this->fldSection = "header";
down below in another function:
$_ENV['validate'][$this->fldSection][$this->name] = $params;
This is working fine in PHP 5.6. However this gives the infamous "Cannot use string offset as an array.." error in PHP 7.1.1 for $this->fldSection = 'header' when it is set in the $_ENV variable
All my variables are dynamically filled. Is there a different/better way to accomplish this in PHP 7.1.1?
I finally cracked the reason for this issue. I'm using the super-global $_ENV to store my values and trying to assign variable-variables to it. However from PHP documentation I find that variable-variables are not supported on super-globals. I changed the variable to $GLOBAL instead of $_ENV (like below) and it worked.
$GLOBAL['validate'][$this->fldSection][$this->name] = $params;
I'm not sure why it worked on 5.6 and not on 7.1. I guess PHP has probably started enforcing those rules strictly only from v7.
I was working with old legacy code and checked if it's running with PHP7. I got an exception (Array to string conversion) with following code:
json_decode($json_string)
->$array['id']
->foo
What helped was to use the curly brackets:
json_decode($json_string)
->{$array['id']}
->foo
My question is, was that already wrong PHP5 and if not, which change is the reason for that? Could not find anything because did not know for what to search... One idea I had is that the new introduced AST produces this behavior?
I think you are right. From what I know in PHP5 that works without any exception, but PHP 7 wants to be just a little bit more strict, because cases like this can cause a lot big problems after when not used correctly.
So i have an Api call where i get a json array:
When i do the following:
$data = $this->HasOffers->get_full_detail_report()['data']['data'];
$this->set('data',$data);
i get an error saying an internal error has occoured
However if i do:
$data = $this->HasOffers->get_full_detail_report();
$data2 = $data['data']['data'];
$this->set('data',$data2);
everything is working correctly.
Now my question is why is this happening? and how can i fix it?
The syntax you are using in the first example is only available in PHP >= 5.4. See relevant section of PHP manual: http://php.net/manual/en/language.types.array.php#example-88
You can see an example running in different versions of PHP at: http://3v4l.org/XhCKH
Your CakePHP site likely has error reporting turned off so, rather than displaying the syntax error, it is displaying an Internal Error.
I'm guessing you have debug < 2, so the description of the error is not very detailed. However, that behaviour is known to be a PHP < 5.4 issue (post regarding that subject).
To "fix" it, you need to upgrade PHP to 5.4 at least. Or, just use an intermediary variable for those cases, it's not that bad.
This is happening because the array you are referencing in the first example only exists after the function get_full_detail_report() is called. PHP does not like this. PHP wants your array to exists before you reference it. I assume that it attempts to locate any variables within your statement before performing any operations, which would mean it is searching for an array that does not exist until it performs those operations.
If anyone has any more insight into this, I would welcome their revisions / comments.
As many of you already know, PHP 5.4 alpha has been released. I have a question regarding the following.
Simplified string offset reading.
$str[1][0] is now a legal construct.
How exactly does $str[1][0] work?
EDIT: http://php.net/releases/NEWS_5_4_0_alpha1.txt
It just means that when reading a string offset PHP returns a string again, on which you again can access an offset. (And on that access yet another offset. It gets funny with $str[0][0][0][0][0][0])
Before PHP 5.4 you would get an "Cannot use string offset as an array" error.
This is a side effect, and was mentioned in the proposal here:
http://php.markmail.org/thread/yiujwve6zdw37tpv
The feature is speed/optimization of string offsets.
Hi,
Recently I noticed that reading of
string offset is performed in two
steps. At first special string_offset
variant of temporary_variable is
created in
zend_fetch_dimension_address_read()
and then the real string value is
created in
_get_zval_ptr_var_string_offset().
I think we can create the real string
in the first place. This makes 50%
speed-up on string offset reading
operation and allows to eliminate some
checks and conditional brunches in VM.
The patch is attached (don't forget to
regenerate zend_vm_execute.h to test
it). However it changes behavior in
one bogus case. The following code now
will emit "b" (currently it generates
a fatal error - cannot use string
offset as an array).
$str = "abs";
var_dump($str[1][0]);
I think it's not a problem at all. "b"
makes sense because "abs"[1] -> "b"
and "b"[0] -> "b".
I'm going to commit the patch in case
of no objections.
Thanks. Dmitry.
This can actually create some interesting bugs when you upgrade code from php 5.3 to 5.4.
In 5.3 this construct would return false:
$array = array("This is a string");
echo isset($array[0][0][0]);
In 5.4 this would return true.