I recently saw this line in a PHP piece of code:
$dbObject = json_decode($jsonString);
$dbObject->{'mysql-5.4'}[0]->credentials
What does this mean? In the PHP docs we can read, that
Both square brackets and curly braces can be used interchangeably for accessing array elements (e.g. $array[42] and $array{42} will both do the same thing in the example above).
But how can the Object $dbObject be defined to allow ->{...}[...]access? Is this code kind of unsafe? Which PHP version does allow this?
Did I miss anything in the PHP docs?
It's to enable access to properties which would be invalid syntax as bare literals. Meaning:
$dbObject->mysql-5.4[0]->credentials
This is invalid/ambiguous syntax. To make clear to PHP that mysql-5.4 is a property and not a property minus a float, you need to use the {'..'} syntax.
To be exact, ->{..} enables you to use any expression as the property name. For example:
$dbObject->{ sprintf('%s-%.1f', 'mysql', 5.4) }
The curly brace syntax allows you to use a string literal or variable as a property or method name.
This is useful for several reasons:
(per #Deceze's answer): It allows you to access property names that would otherwise not be valid PHP syntax -- eg if the property name contains a dot or dash, per your example. Typically properties like this would be accessed via a __get() magic method, since they would also be invalid syntax to define as an actual property within the class.
(per #feela's answer): It allows you to use variables to reference your properties. This is similar to the $$ variable variable syntax. It's generally not really very good practice, but is useful in some cases.
(not mentioned by any other answers yet): It allows you to remove certain potential ambiguities from your code. Consider the following code for example:
$output = $foo->$bar['baz'];
This is ambiguous. You can resolve the ambiguity by adding braces or brackets:
$output = $foo->{$bar['baz']}; //gets the value of a property from $foo which has a name that is defined in $bar['baz']
$output = ($foo->$bar)['baz']; //gets the ['baz'] element of $foo->$bar array.
This is particularly important because the forthcoming relese of PHP 7 will change the default behaviour of code like like. This will make the language behave more consistently, but will break existing code that doesn't have the braces.
See also the PHP documentation for this change here: https://wiki.php.net/rfc/uniform_variable_syntax
But even without the language change to force the issue, code like this should have braces anyway to help with readability -- if you don't put braces, then you may end up struggling to work out what you were trying to do when you come back to the code in six months' time.
The curly braces syntax in the example is not from the array syntax, but comes from a possible syntax to access variables with variable names.
Curly braces may also be used, to clearly delimit the property name.
They are most useful when accessing values within a property that
contains an array, when the property name is made of mulitple parts,
or when the property name contains characters that are not otherwise
valid (e.g. from json_decode() or SimpleXML).
Examples from the PHP docs:
echo $foo->{$baz[1]} . "\n";
echo $foo->{$start . $end} . "\n";
echo $foo->{$arr[1]} . "\n";
See “PHP Variable variables”: http://php.net/manual/en/language.variables.variable.php
(More examples on the usage there…)
As an addition to #deceze's answer:
The -> operator means that you are accessing an object property. In this case the property name should be mysql-5.4 which is not valid PHP identifier (it must contain letters, numbers or underscores, see here). So it is 100% sure that the property name has been created dynamically.
PHP allows overloading properties using magic method called __get(). The body of this method allows you to handle any property you would wish - this can be any string, or any variable, even an object, which is cast to a string.
So in your case somebody created a class with a __get() magic method that handles string mysql-5.4. The curly braces { and } are given to denote that the string should be treated as property name (however there is no property with this name).
most of the time there is a $ after ->{ so it's like ->$variable
for example we have:
$languageCode = 'en';
$obj->{$languageCode};
$obj->{$languageCode} it is equivalent to $obj->en
============
in your case it's because it's not allowed in php write like:
$dbObject->mysql-5.4
because there is a - and there is a . in the mysql-5.4 and - and . makes a word to two words.
so you have to write it like this:
$dbObject->{'mysql-5.4'}[0]->credentials
Related
I just stumbled upon an interesting syntax in a PHP script:
echo $foo->{'bar'};
$foo in this case is an object returned from PHP's json_decode() function, but it works well when accessing public members of any object.
I've tried to find out why this syntax was used instead of the more common:
echo $foo->bar;
Does accessing a class member with the syntax from the first example offer anything special, compared to the second example?
The curly bracket syntax is useful when you want to reference a function name as a string:
print $foo->{'aMemberFunc'}();
When you want access members which name is provided by another function (or a variable).
Here getVarName() returns a string which can be used to reference a member inside the $foo object.
print $foo->{getVarName()};
Without the curly brackets it would be $foo->getVarName() and it would try and run that method... with the curly brackets it takes a completely different meaning.
echo $foo->{'bar'}; and echo $foo->bar; are identical as far as I can tell.
first syntax allows you to access properties with '-', often used in JSON.
The benefit is that you can have variables names that don't adhere to the rules for naming member variables.
This might seem like a bad idea and usually it is but there are uses for it. An example would be if you were writing an application that allowed its users to add arbitrary fields with human readable names but still be accessible for plugins etc.
I get the basics of variable variables, but I saw a syntax just know, which bogles my mind a bit.
$this->{$toShow}();
I don't really see what those {} symbols are doing there. Do they have any special meaning?
PHP's variable parser isn't greedy. The {} are used to indicate what should be considered part of a variable reference and what isn't. Consider this:
$arr = array();
$arr[3] = array();
$arr[3][4] = 'Hi there';
echo "$arr[3][4]";
Notice the double quotes. You'd expect this to output Hi there, but you actually end up seeing Array[4]. This is due to the non-greediness of the parser. It will check for only ONE level of array indexing while interpolating variables into the string, so what it really saw was this:
echo $arr[3], "[4]";
But, doing
echo "{$arr[3][4]}";
forces PHP to treat everything inside the braces as a variable reference, and you end up with the expected Hi there.
They tell the parser, where a variable name starts and ends. In this particular case it might not be needed, but consider this example:
$this->$toShow[0]
What should the parser do? Is $toShow an array or $this->$toShow ? In this case, the variable is resolved first and the array index is applied to the resulting property.
So if you actually want to access $toShow[0], you have to write:
$this->{$toShow[0]}
These curly braces can be used to use expressions to specify the variable identifier instead of just a variable’s value:
$var = 'foo';
echo ${$var.'bar'}; // echoes the value of $foobar
echo $$var.'bar'; // echoes the value of $foo concatenated with "bar"
$this->{$toShow}();
Break it down as below:
First this is a object oriented programming style as you got to see $this and ->. Second, {$toShow}() is a method(function) as you can see the () brackets.
So now {$toShow}() should somehow be parsed to a name like 'compute()'. And, $toShow is just a variable which might hold a possible function name. But the question remains, why is {} used around.
The reason is {} brackets substitues the value in the place. To clarify,
$toShow="compute";
so,
{$toShow}(); //is equivalent to compute();
but this is not true:
$toShow(); //this is wrong as a variablename is not a legal function name
I'm trying to get a constant string and index it as if it was an array of characters (square bracket syntax). When I try this code it fails on the last line.
define( 'CONSTANT_STRING','0123456789abcdef');
echo CONSTANT_STRING; // Works by itself :)
$string = CONSTANT_STRING;
echo $string[9]; // Also works by itself.
echo strlen(CONSTANT_STRING); // Also works by itself.
echo substr(CONSTANT_STRING, 9, 1); // Ok, yes this works, but not as clean.
echo CONSTANT_STRING[9]; // Fails as a syntax (parse) error.
I am using a constant string like this in a function. Since it could be called multiple times on one page it really should be a constant. What is the best option if there is no way to do this like I originally intended.
PHP Constants can only be scalar values, so the engine doesn't try to properly parse a constant that's used as something more than a scalar, like an array or an object.
This is a problem in your case because the brackets are used to point at an array index and can be used as a shortcut to grab a character at a specific location in the string.
You'll just have to do it the "hard" way and use substr().
Is it okay to use array without single or double quotion like $array[key]? I thought it is bad because PHP look for constant first if I don't use single or double quotation. One of my colleagues told me that it does not matter.
What do you guys think?
It is not considered as OK -- even if it will work in most cases.
Basically, when PHP sees this :
echo $array[key];
It will search for a constant, defined with define, called key -- and, if there is none, if will take the 'key' value.
But, if there is something like this earlier in your code :
define('key', 'glop');
It will not take
echo $array['key'];
anymore ; instead, it'll use the value of the key constant -- and your code will be the same as :
echo $array['glop'];
In the end, not putting quotes arround the key's name is bad for at least two reasons :
There is a risk that it will not do what you expect -- which is very bad
It might, today...
But what about next week / month / year ?
Maybe, one day, you'll define a constant with the wrong name ;-)
It's not good for performance :
it has to search for a constant, before using 'key'
And, as said in a comment, it generates notices (even if you disable error_reporting and display_errors, the notices/warnings/errors are still generated, even if discarded later)
So : you should not listen to that guy on this point : he is wrong : it does matter.
And if you need some "proof" that's "better" than what people can tell you on stackoverflow, you can point him to this section of the manual, as a reference : Why is $foo[bar] wrong?
This is not okay and to add to what others have said, it will trigger an error in most cases:
8 Notice Use of undefined constant key - assumed 'key' in file: 'index.php' on line 46
See the section in the PHP Manual for "Why is $foo[bar] wrong?" under "Array do's and don'ts" on this page: http://php.net/manual/en/language.types.array.php
This is wrong and will auto-define a constant:
$var = $array[bar];
This usage however is correct:
$var = "string $array[bar] ...";
For compatibility with PHP2 this old syntax is still allowed in string context. Quoting the key would lead to a parse error, unless you also use { curly braces } around it.
From the PHP Manual - Why is $foo[bar] wrong?
Always use quotes around a string literal array index. For example, $foo['bar'] is correct, while $foo[bar] is not. But why? It is common to encounter this kind of syntax in old scripts:
<?php
$foo[bar] = 'enemy';
echo $foo[bar];
// etc
?>
This is wrong, but it works. The reason is that this code has an undefined constant (bar) rather than a string ('bar' - notice the quotes). PHP may in future define constants which, unfortunately for such code, have the same name. It works because PHP automatically converts a bare string (an unquoted string which does not correspond to any known symbol) into a string which contains the bare string. For instance, if there is no defined constant named bar, then PHP will substitute in the string 'bar' and use that.
There is some more examples in the manual for you to check out.
Unless the key actually is a constant, there is no reason for you not to be putting quotes around the key.
The way PHP works is it looks for the constant value of what you've put, but it takes the string representation of it if the constant cannot be found.
If someone were to edit your code down the road and add a constant with that key name, it would just cause more headaches.
It's bad practice to not quote key values, for a number of reasons:
Potential collisions with meaningful symbol names, such as define'd constants.
Some keys can't be expressed without quoting (for instance, the key "]").
Bad habits can bite you later on (namely in regards to #1 and #2).
Performance - searching for define's takes time.
If you're wanting to avoid typing quotes around names that are just standard elements of a thing you're passing around a lot, perhaps you might want to use objects instead, which take a object->property syntax instead of an $array["element"] syntax.
First question on SO and it's a real RTM candidate. But I promise you I've looked and can't seem to find it. I'll happily do a #headpalm when it turns out to be a simple thing that I missed.
Trying to figure out Zend Framework and came across the following syntax:
$this->_session->{'user_id'}
I have never seen the curly braces syntax used to access what appears to be a member variable. How is it different than
$this->_session->user_id
I'm assuming that the _session is irrelevant, but including it in the question since it may not be.
Are the curly braces just a cleanliness convention that attempts to wrap the compound variable name user_id? Or is it some kind of a special accessor?
Any pointers into TFM so I can R up would be humbly appreciated.
Many thanks. Please be gentle.
Curly braces are used to explicitly specify the end of a variable name. For example:
echo "This square is {$square->width}00 centimeters broad.";
So, your case is really a combination of two special cases. You're allowed to access class variables using curly braces and like so:
$class->{'variable_name'} // Same as $class->variable_name
$class->{'variable' . '_name'} // Dynamic values are also allowed
And in your case, you're just surrounding them with the curly brace syntax.
See the PHP manual, "complex (curly) syntax."
I know the syntax just when using variable variables:
$userProp = 'id';
$this->_session->{'user_'.$userProp};
Theres probably one big advantage of that syntax, however, its generally in the domain of hairy stuff, and things you probably want to avoid.
It permits you to use characters in variable names that are otherwise unpermitted.
ie:
$this->object->{"hello world\0\n"}
$this->object->{"function(){ this is a truely awful name for a variable }"}
In the example you give, there's no real difference, and IMO $this->_session->user_id should be used because it's clearer.
What the curly brace syntax is actually good for is accessing a member variable by constructing an expression for its name, like $this->_session->{'user_id' . $index}.
The two examples in your question do the same thing. PHP allows you to access member data/methods in several ways...
object->{'name_of_member'};
object->name_of_member;
$member = 'name_of_member';
object->$member;