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.
Related
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.
Is there any way to easily fix this issue or do I really need to rewrite all the legacy code?
PHP Fatal error: Call-time pass-by-reference has been removed in ... on line 30
This happens everywhere as variables are passed into functions as references throughout the code.
You should be denoting the call by reference in the function definition, not the actual call. Since PHP started showing the deprecation errors in version 5.3, I would say it would be a good idea to rewrite the code.
From the documentation:
There is no reference sign on a function call - only on function definitions. Function definitions alone are enough to correctly pass the argument by reference. As of PHP 5.3.0, you will get a warning saying that "call-time pass-by-reference" is deprecated when you use & in foo(&$a);.
For example, instead of using:
// Wrong way!
myFunc(&$arg); # Deprecated pass-by-reference argument
function myFunc($arg) { }
Use:
// Right way!
myFunc($var); # pass-by-value argument
function myFunc(&$arg) { }
For anyone who, like me, reads this because they need to update a giant legacy project to 5.6: as the answers here point out, there is no quick fix: you really do need to find each occurrence of the problem manually, and fix it.
The most convenient way I found to find all problematic lines in a project (short of using a full-blown static code analyzer, which is very accurate but I don't know any that take you to the correct position in the editor right away) was using Visual Studio Code, which has a nice PHP linter built in, and its search feature which allows searching by Regex. (Of course, you can use any IDE/Code editor for this that does PHP linting and Regex searches.)
Using this regex:
^(?!.*function).*(\&\$)
it is possible to search project-wide for the occurrence of &$ only in lines that are not a function definition.
This still turns up a lot of false positives, but it does make the job easier.
VSCode's search results browser makes walking through and finding the offending lines super easy: you just click through each result, and look out for those that the linter underlines red. Those you need to fix.
PHP and references are somewhat unintuitive. If used appropriately references in the right places can provide large performance improvements or avoid very ugly workarounds and unusual code.
The following will produce an error:
function f(&$v){$v = true;}
f(&$v);
function f($v){$v = true;}
f(&$v);
None of these have to fail as they could follow the rules below but have no doubt been removed or disabled to prevent a lot of legacy confusion.
If they did work, both involve a redundant conversion to reference and the second also involves a redundant conversion back to a scoped contained variable.
The second one used to be possible allowing a reference to be passed to code that wasn't intended to work with references. This is extremely ugly for maintainability.
This will do nothing:
function f($v){$v = true;}
$r = &$v;
f($r);
More specifically, it turns the reference back into a normal variable as you have not asked for a reference.
This will work:
function f(&$v){$v = true;}
f($v);
This sees that you are passing a non-reference but want a reference so turns it into a reference.
What this means is that you can't pass a reference to a function where a reference is not explicitly asked for making it one of the few areas where PHP is strict on passing types or in this case more of a meta type.
If you need more dynamic behaviour this will work:
function f(&$v){$v = true;}
$v = array(false,false,false);
$r = &$v[1];
f($r);
Here it sees that you want a reference and already have a reference so leaves it alone. It may also chain the reference but I doubt this.
Is there any way to easily fix this issue or do I really need to rewrite all the legacy code?
PHP Fatal error: Call-time pass-by-reference has been removed in ... on line 30
This happens everywhere as variables are passed into functions as references throughout the code.
You should be denoting the call by reference in the function definition, not the actual call. Since PHP started showing the deprecation errors in version 5.3, I would say it would be a good idea to rewrite the code.
From the documentation:
There is no reference sign on a function call - only on function definitions. Function definitions alone are enough to correctly pass the argument by reference. As of PHP 5.3.0, you will get a warning saying that "call-time pass-by-reference" is deprecated when you use & in foo(&$a);.
For example, instead of using:
// Wrong way!
myFunc(&$arg); # Deprecated pass-by-reference argument
function myFunc($arg) { }
Use:
// Right way!
myFunc($var); # pass-by-value argument
function myFunc(&$arg) { }
For anyone who, like me, reads this because they need to update a giant legacy project to 5.6: as the answers here point out, there is no quick fix: you really do need to find each occurrence of the problem manually, and fix it.
The most convenient way I found to find all problematic lines in a project (short of using a full-blown static code analyzer, which is very accurate but I don't know any that take you to the correct position in the editor right away) was using Visual Studio Code, which has a nice PHP linter built in, and its search feature which allows searching by Regex. (Of course, you can use any IDE/Code editor for this that does PHP linting and Regex searches.)
Using this regex:
^(?!.*function).*(\&\$)
it is possible to search project-wide for the occurrence of &$ only in lines that are not a function definition.
This still turns up a lot of false positives, but it does make the job easier.
VSCode's search results browser makes walking through and finding the offending lines super easy: you just click through each result, and look out for those that the linter underlines red. Those you need to fix.
PHP and references are somewhat unintuitive. If used appropriately references in the right places can provide large performance improvements or avoid very ugly workarounds and unusual code.
The following will produce an error:
function f(&$v){$v = true;}
f(&$v);
function f($v){$v = true;}
f(&$v);
None of these have to fail as they could follow the rules below but have no doubt been removed or disabled to prevent a lot of legacy confusion.
If they did work, both involve a redundant conversion to reference and the second also involves a redundant conversion back to a scoped contained variable.
The second one used to be possible allowing a reference to be passed to code that wasn't intended to work with references. This is extremely ugly for maintainability.
This will do nothing:
function f($v){$v = true;}
$r = &$v;
f($r);
More specifically, it turns the reference back into a normal variable as you have not asked for a reference.
This will work:
function f(&$v){$v = true;}
f($v);
This sees that you are passing a non-reference but want a reference so turns it into a reference.
What this means is that you can't pass a reference to a function where a reference is not explicitly asked for making it one of the few areas where PHP is strict on passing types or in this case more of a meta type.
If you need more dynamic behaviour this will work:
function f(&$v){$v = true;}
$v = array(false,false,false);
$r = &$v[1];
f($r);
Here it sees that you want a reference and already have a reference so leaves it alone. It may also chain the reference but I doubt this.
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.
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.