Class constant in a string in PHP - php

My reading of the manual (the bit just before the section heading "String access and modification by character") is that you can do some fancy tricks with class constants and {} inside a string but you can't do the simple thing that would make this method return the truth:
class c {
const k = '12';
public function s() {
return "Twelve in decimal is {c::k}.";
}
}
Is the right solution here to concatenate?

Is the right solution here to concatenate?
Yes. The extended curly syntax doesn't support it.
Alternatively, you could export the list of constants to an array and use it (or export the constant to a single scalar variable name), but that's not really a good solution IMO.
Note that constants are available, as you can do this:
const k = 'foo';
$foo = 'bar';
echo "{${c::k}}"
giving you bar, but that's not what you want.

It's a little cryptic, but there is a note on this in the manual.
Functions, method calls, static class variables, and class constants inside {$} work since PHP 5. However, the value accessed will be interpreted as the name of a variable in the scope in which the string is defined. Using single curly braces ({}) will not work for accessing the return values of functions or methods or the values of class constants or static class variables.
The last sentence tells you it won't work so yes, concatenation is the way to go here.
(modified) Example of above paragraph:
<?php
class beers {
const softdrink = 'rootbeer';
}
$rootbeer = 'A & W';
// This works; outputs: I'd like an A & W
echo "I'd like an {${beers::softdrink}}\n";
// This won't work; outputs: I'd like an {beers::softdrink}
echo "I'd like an {beers::softdrink}\n";

The curly syntax only works for 'variable expressions'. And you need anything that you can access with {$.
Oh, there's only that workaround:
$c = "constant";
return "Twelve in decimal is {$c('c::k')}.";
Which is obviously not much shorter or more readable than just using string concatenation here.

Related

PHP - Difference in creating variable variables with brackets or double dollar signs?

From what I can tell in the PHP Manual, it doesn't seem like there is much difference between defining a variable variable with double brackets or double dollar signs.
$foo = 'hello';
$$foo = 'hi';
echo $hello; // 'hi'
$baz = 'goodbye';
${$baz} = 'bye';
echo $goodbye; // 'bye'
The only difference it mentions in the manual is when using arrays. Is there any other noticeable difference between the two? Which one is better for which situations?
Both versions are basically the same.
The curly braces notation is used in cases where there could be ambiguity:
$foo = 'bar';
$bar = [];
${$foo}[] = 'foobar';
var_dump($bar); // foobar
If you'd omit the braces in the above example, you'd get a fatal error, with the braces, it works fine.
However, I would recommend avoiding dynamic variable names altogether. They are funny to use and may save some space. But in the end, your code will become less readable and you will have trouble debugging.
In this case, there is no difference. It is like using parentheses to group operators, even when they are not necessary.

What does { } do within a string?

$name = "jason";
$p = "hello-{hello2}-$name-{$name}";
echo $p;
output :
hello-{hello2}-jason-jason
Came across some examples of prepared statements and noticed this. If its encompassing a variable, it removes them, otherwise it keeps them. Why is this behavior necessary when
echo "$name";
gets you the same result as
echo "{$name}";
or is it just readability?
It's used as a delimiter for variables in strings. This is necessary in some cases, as PHP's string parser isn't Greedy aand will mis-interpret many common structs.
e.g.
$foo = array();
$foo['bar'] = array();
$foo['bar']['baz'] = 'qux';
echo "Hello $foo[bar][baz]";
will actually print
Hello Array[baz]
Because it's parsed as
echo "Hello ", $foo['bar'], "[baz]";
^ ^ ^
string array string
Using {} forces PHP to consider the array reference as single entity:
echo "Hello, {$foo['bar']['baz']}"; // prints "Hello, qux"
It also helps differentiate ambiguous stuff
$foo = 'bar';
echo "$foos" // undefined variable 'foos'
echo "{$foo}s" // variable containing 'bar' + string 's'
It's something called "complex syntax"
From php.net you can go to Complex (curly) syntax section and see many examples.
Complex (curly) syntax
This isn't called complex because the syntax is complex, but because it allows for the use of complex expressions.
Any scalar variable, array element or object property with a string representation can be included via this syntax. Simply write the expression the same way as it would appear outside the string, and then wrap it in { and }. Since { can not be escaped, this syntax will only be recognised when the $ immediately follows the {. Use {\$ to get a literal {$.
Functions, method calls, static class variables, and class constants inside {$} work since PHP 5. However, the value accessed will be interpreted as the name of a variable in the scope in which the string is defined. Using single curly braces ({}) will not work for accessing the return values of functions or methods or the values of class constants or static class variables.
It does not necessarily generate the same output:
$name = 'foo';
$names = 'bar';
echo "Output1: $names";
echo "Output2: {$name}s";
Output
Output1: bar
Output2: foos
Also you can access complex structures via the curly syntax like {$foo->bar}.
This syntax is useful when you want to display variable following some string and you don't want any space between them.
Compare the following:
<?php
$name='John';
echo "My name is $nameathan. I'm twenty years old<br />";
echo "My name is {$name}athan. I'm twenty years old<br />";
It will give you result:
Notice: Undefined variable: nameathan in ... on line 5
My name is . I'm twenty years old
My name is Johnathan. I'm twenty years old
For first echo it will generate notice and won't work as expected because PHP doesn't know that you want to use variable $name in the string and not $nameathan. Using curly braces in second case solves the issue.
Of course you can concatenate string this way:
echo "My name is $name"."athan. I'm twenty years old<br />";
and it also solves the issue but if you have many such variables in string it will be much more convenient to use curly braces.

PHP variable variables in {} symbols

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

Constants inside quotes are not printed?

This prints apple:
define("CONSTANT","apple");
echo CONSTANT;
But this doesn't:
echo "This is a constant: CONSTANT";
Why?
Because "constants inside quotes are not printed". The correct form is:
echo "This is a constant: " . CONSTANT;
The dot is the concatenation operator.
define('QUICK', 'slow');
define('FOX', 'fox');
$K = 'strval';
echo "The {$K(QUICK)} brown {$K(FOX)} jumps over the lazy dog's {$K(BACK)}.";
If you want to include references to variables inside of strings you need to use special syntax. This feature is called string interpolation and is included in most scripting languages.
This page describes the feature in PHP. It appears that constants are not replaced during string interpolation in PHP, so the only way to get the behavior you want is to use the concatenation that Artefacto suggested.
In fact, I just found another post saying as much:
AFAIK, with static variables, one has
the same 'problem' as with constants:
no interpolation possible, just use
temporary variables or concatenation.
Concatenation has been suggested as the only solution here, but that doesn't work when using syntax like:
define("MY_CONSTANT", "some information");
$html = <<< EOS
<p>Some html, **put MY_CONSTANT here**</p>
EOS;
Of course, the above just puts the text 'MY_CONSTANT' in $html.
Other options include:
define a temporary variable to hold the constant:
$myConst = MY_CONSTANT;
$html = <<< EOS
<p>Some html, {$myConst} </p>
EOS;
if there are many constants, you can get an array of them all and use that:
$constants = get_defined_constants();
$html = <<< EOS
<p>Some html, {$constants["MY_CONSTANT"]} </p>
EOS;
Of course, in such a trivially short example, there's no reason to use the <<< operator, but with a longer block of output the above two may be much clearer and easier to maintain than a bunch of string concatenation!
The question was already answered, but I'd like to provide a more generic insight on this.
In double quotes, PHP recognizes anything starting with a $ as a variable to be interpolated. Further more, it considers array and object access ([] and ->) but only up to a single level. E.g. "$foo->bar" interpolates $foo->bar and $foo->bar->baz does the same thing and treats ->baz as a string literally. Also, the quotes in [] must be ommited for string keys. E.g. "$foo[bar]" interpolates $foo['bar'] while "$foo['bar']" is a syntax error. AFAIK, that's it. To get more functionality, you need the "{$...}" syntax.
The $ here is actually a part of the syntax and it doesn't work without it. E.g. "{FOO}" will not interpolate a constant FOO, it's simply a syntax error. However, other than some strange syntactical restrictions, this construct is actually quite strong and may contain any valid PHP expression, as long as it starts with a $ and is an array access, object access, or a function call. (Maybe some other cases are permitted to. Please let me know, if anyone has a better understanding of this.) The most general solution to your problem would be to define something like the following function somewhere in your code base:
$id = function ($x) {
return $x;
}
It's simply the identity function - it returns whatever you give it. It must be defined as an anonymous function, so you can refer to it as $id with the $.
Now you can use this function to interpolate any PHP expression:
echo "{$id(CONSTANTS)}"
echo "{$id($some + $operators - $as . $well)}"
// etc...
Alternative for PHP versions < 5.3 where you can't use anonymous functoins:
class Util {
function id ($x) { return $x; }
}
$u = new Util;
echo "{$u->id(ANY + $expression . $here)}"
// or...
function id ($x) { return $x; };
$id = 'id';
echo "{$id(ANY + $expression . $here)}"
The native interpolation does not support constants. Still not up to PHP 8.2 (and maybe later on). An alternative to echo is to use printf() or sprintf() for getting the interpolation result as string.
const MY_CONSTANT = "foo";
printf("Hello %s bar!", MY_CONSTANT);

PHP class constant string variable spanning over multiple lines

I want to have a string variable for a PHP class, which would be available to all methods.
However, this variable is quite long, so I want to separate it into multiple lines.
For example,
$variable = "line 1" .
"line 2" .
"line 3";
But above doesn't work.
I tried EOD, but EOD is not allowed within class. And when I declare it outside the class, I can't access the variable from within the class.
What is the best way?
If you are using PHP >= 5.3, you could use HEREDOC syntax to declare your string :
class MyClass {
public $str = <<<STR
this is
a long
string
STR;
}
$a = new MyClass();
var_dump($a->str);
But this :
is only possible with PHP >= 5.3
and the string must not contain any variable
this is because the string's value must be known at compile-time
which, btw, explains why the concatenation, with the ., will not work : it's done at execution time.
And another drawback is that this will put newlines in the string -- which might, or not, be a bad thing.
If you are using PHP <= 5.2 :
You can't do that ; a solution could be to initialize the string in your class' constructor :
class MyClass {
public $str;
public function __construct() {
$this->str = <<<STR
this is
a long
string
STR;
}
}
(same not with newlines)
Or, here, you can do strings concatenations :
class MyClass {
public $str;
public function __construct() {
$this->str = 'this is' .
'a long' .
'string';
}
}
(this way, no newlines)
Else, you can have a string that's surrounded by either single or double quotes, and put it on several lines :
class MyClass {
public $str = "this is
a long
string";
}
(Here, again, you'll have newlines in the resulting string)
$var = "this is a really long variable and I'd rather have it " .
"span over multiple lines for readability sake. God it's so hot in here " .
"can someone turn on the A/C?";
echo $var;
Which outputs:
this is a really long variable and I'd rather have it span over multiple lines for readability sake. God it's so hot in here can someone turn on the A/C?
What you have now works using the string concatenation operator. If you can post more information regarding your issue, some code or perhaps a further explanation of how it doesn't work. More information will lead you to a better answer.
I'm using PHP 5.5.9 and have come across a similar issue only with class constants. I want to use a somewhat long string as a constant but I don't want:
really long lines of code
newlines showing up in the text at the break points
the property to be mutable
the property to be inaccessible outside the class
I think the solution here is something that is done a lot in the Laravel 5 scaffolding and why they kept doing this had me baffled until now. What they do is something like:
public static function getLongPropertyString()
{
return 'A a string that can be arbitrarily long and contain as ' .
'many breaks in the code as you want without line breaks ' .
'appearing in the resulting string.';
}
This method provides an immutable string. You don't strictly get that by creating a protected/private variable with getters since its still mutable internally. Only changing the code or overriding can change this string. Another pro is that making it static allows a single "instance" per class.
Unfortunately, now your code would be Class::getProperty() rather than just Class::property. Another downside is that the concatenation would be done every time you call the function but depending on how you use this, that cost is typically negligible.
It would be cool if the PHP compiler were able to recognize that the concatenation operation on only values already known at compile time can be run at compile time and the result substituted (beings more knowledgeable than myself know why this is so).

Categories