Is array error possibly a PHP version issue? - php

I work on a website that, since last Oct, has had the following lines of code that work just fine:
if(empty($post_types))
{
$post_types[] = 'post';
$post_types[] = 'product-list';
}
I had not seen this construct in PHP before, (and since I started my programming work in C, it's a little irritating), but it works.
We started a second site with the same technology and basic setup that threw the following error at the same lines of code,
"Uncaught Error: [] operator not supported for strings ..."
The sites are hosted at the same place, but I noticed that they are using different 7.x versions of PHP. I did a bit of research to see if the behavior is due to a change in PHP 7.3, but I didn't find an answer.
Please note that my question is on whether this situation is possibly a PHP version issue, not how to solve the array problem, which I changed with
$post_types = array('post', 'product-list');

I found your answer in the PHP docs Creating/modifying with square bracket syntax:
$arr[key] = value;
$arr[] = value;
// key may be an integer or string
// value may be any value of any type
If $arr doesn't exist yet, it will be created, so this is also an
alternative way to create an array. This practice is however
discouraged because if $arr already contains some value (e.g. string
from request variable) then this value will stay in the place and []
may actually stand for string access operator. It is always better to
initialize a variable by a direct assignment.
Note: As of PHP 7.1.0, applying the empty index operator on a string throws a fatal error. Formerly, the string was silently converted to
an array.
So it appears there is a change in PHP 7.1.0 matching with the problem you described.
In your code, your $post_type variable must be initialized as a string [EDIT : I could only reproduce the problem with an empty string], and was previously ( PHP < 7.1.0) silently converted to an array.

Related

Warnings: Array to string conversion, undefined property in PHP 8.1 trying to call a property of an object (worked in PHP 5.5) [duplicate]

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

How to fix simpleXML “Warning: Illegal string offset” for node name?

I work with simpleXML to parse some XML responses from server, which I load like this:
$xml = simplexml_load_string($string);
It has a one and only one child, but with different names for different responses, so I get child name first:
$node = $xml->children()->getName();
I make new object Response and set his properties to what I read from that XML string:
return (new Response())
->setTime((string)$xml['time'])
->setId((string)$xml->$node['id'])
->setResult((string)$xml->$node['result'])
->setBalance((string)$xml->$node->balance['value']);
And here this warning comes - Illegal string offset 'id', Illegal string offset 'result'
I know, that $node is actually a string, but it used as name of the node in response.
If I change my code to ->setId((string)$xml->result['id']), the warning disappear.
The problem, that I do not know the name of the node, before response actually comes
(for example it can be "good_result", "result_1" and so on).
So, the '$node['id']' is not ask for string index, but for attribute of node.
It looks like collision between PHP string index syntax and simpleXML node name syntax.
The code itself work just fine, warning comes only in IDE
There are a lot of similar questions about simpleXML, but no answer to my case
I need just to remove that warning, so answer how to fix it in code, or remove such warnings are accepted
There are two possible ways to interpret code of this form:
$object->$foo['bar'];
Versions of PHP since 7.0 will look up the property identified by $foo, and then look up the key 'bar' on the result, which is what you want.
Older versions of PHP would evaluate $foo['bar'] first, and then look up the property based on that result.
The warning in your IDE is assuming the old interpretation: it's warning you that $foo['bar'] doesn't make sense, because $foo is a string.
Unless you're actually running your code in an ancient version of PHP (5.6 hasn't had an official security update for over 2 years), there is no actual problem with the code. You need to either upgrade your IDE, or re-configure it, so that it interprets code the same way the actual PHP will. Since you don't mention what IDE you're using, I can't be more specific.

PHP missing notices

here are some X-files.
Let's check this script: https://admin.laysoft.tk/test.php
We tested it on different machines with different version of PHP.
Let's see this:
$tomb = 666;
var_dump($tomb);
$a = $tomb['akarmi'];
var_dump($a);
Result of this is:
int(666)
NULL
($tomb means array)
As you see, we initialized the $tomb as an integer.
Why $a = $tomb['akarmi']; does not drop a notice, that no key like this?
UPDATE
I've reported it, I am so curious.
https://bugs.php.net/bug.php?id=74579
UPDATE2
Ok, this bug is exists from years. There are a lot of issue about this:
https://bugs.php.net/bug.php?id=37676
Because of PHP's type juggling feature, which will implicitly convert between types, depending on how you attempt to access a variable.
The conversion to arrays however is not implemented, not even defined how it should work, as the manual says:
The behaviour of an automatic conversion to array is currently undefined.
As for why it has remained that way through the years ... nobody could really answer that question.

PHP 5.4's simplified string offset reading

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.

Why do php function json_decode fail if string contains the word undefined as a value?

I have this string, which is generated by dojo.toJson() function:
{"page":"accommodation task=viewList","language":undefined}
When decoding it with json_decode in php it returns null.
I already figured out that this is caused by the value undefined, but I am not sure if this is to be expected or if it is a bug. Is the above string not valid json? Why can't php just convert undefined to null?
I am using PHP 5.2.10
Because undefined is not valid JSON. JSON doesn't have the JavaScript concept of undefined. It does have null, which is vaguely similar, but the usual thing (for better or worse) is to simply omit properties whose values would be undefined.
I'm surprised if Dojo's toJson produces invalid JSON like that. You might consider using Crockford's JSON.stringify instead. If Dojo's toJson is really doing that, I'd report it as a bug to the Dojo team.
Update: Apparently someone did report it to them, and they closed it as invalid on the "garbage in, garbage out" theory. Not my project, but that's just totally not how I would handle properties with undefined values... I'd omit them or throw an exception.
Update 2: As you may know, the ECMAScript 5th edition specification defines a JSON object with parse and stringify which browsers are adding support for. The specification's definition of JSON.stringify says "undefined values are not rendered" (Section 15.12.3, Note 2) — e.g., the property should be omitted. Perhaps if you point that out to the Dojo team, they'll rethink their GIGO response to the bug report. Also note #Felix's comment below: They omit function references, which also can't be validly represented in JSON, but apply a different rule to undefined.
Update 3: Still broken in Dojo 1.6.1. Here's a live test of v1.6.0, which is the latest on the CDNs. I've also tested v1.6.1 and it's still broken there too. (Not going to post a test page hotlinking to their download section, though, that would be rude.)
You can transform the undefined to null in PHP on the server side, that fixes the immediate issue:
<?php
$json = '{"page":"accommodation task=viewList","language":undefined,"example": "This is an example of an occurence of undefined that remains"}';
$json = preg_replace(
'~undefined(?=(?:[^"]*"[^"\\\\]*(?:\\\\.[^"\\\\]*)*")*[^"]*$)~', 'null', $json
);
var_dump( json_decode( $json ) );
The better solution though would be to make sure 'undefined' will not appear in the JSON, as it is - indeed - invalid.

Categories