I've commented the code for easier readibility.
function logRequest($cached = false) {
// This function logs the number of two types of events: (1) cached and (2) uncached/upstream request
// References to frequently addressed array keys, for brevity
$lc = &$_SESSION['loads']['cache'];
$lu = &$_SESSION['loads']['upstream'];
// Add to one session variable or the other, depending on the type of event
$s = ($cached ? &$lc : &$lu);
$s = (isset($s) ? $s : 0) + 1;
// Begin dumping the counts to a file, but only every 25 calls for each client
if(($lc ?? 0) + ($lu ?? 0) < 25) return;
$logArray = (file_exists($logFile = '../runtime/requests.json') ? json_decode(file_get_contents($logFile),true) : []);
// Define array structure for dumping to a file
$today = (new DateTime())->format('Y-m-d');
$ac = &$logArray[$today]['cache access'];
$au = &$logArray[$today]['upstream request'];
// Do incrementing
$ac = (isset($ac) ? $ac : 0) + $lc;
$au = (isset($au) ? $au : 0) + $lu;
// Reset counters in the session
$lc = $lu = 0;
// Finally, save to file
file_put_contents($logFile, json_encode($logArray, JSON_PRETTY_PRINT));
}
The line I am talking about is this:
$s = ($cached ? &$lc : &$lu);
And the error is:
Parse error: syntax error, unexpected '&' in...
How do I go about assigning a reference in this case? Surely there must be a way to use the ternary operator, right?
P.S. I am a very casual programmer so I would be grateful if you could point out any other bad practices in my code.
try this
$cached ? $s = &$lc : $s = &$lu;
Add some explanation about the code. Sorry for my bad english, I am ashamed to express in English.
If the value of the first subexpression is TRUE (non-zero), then the second subexpression is evaluated, and that is the result of the conditional expression. Otherwise, the third subexpression is evaluated, and that is the value.
this is from php expressions manual.
the reason of we can't use $s = $cached ? &$lc : &$lu; is ternary operator need a expression but &$lc and &$lu not a expression.
we can test this code
<?php
$a = 5;
$a;
It's no error.
but this
<?php
$a = 5;
&$a;
throw an error.
Parse error: syntax error, unexpected '&', expecting end of file in /usercode/file.php on line 3
The above is my opinion, I hope you can understand.
It's too difficult to using english for me.(ㄒoㄒ)
A working alternative would be employing dynamic variable names:
$s = &${$cached ? 'lc': 'lu'};
Further reading: https://stackoverflow.com/a/35772533/9986646
Related
I wanna load variables from a file as string and compare it later
structure of file:
variable name; result
e.g.,
$arr['x'];5
$a;53
$b - $a;27
I load this file (works) and assign first item after split to $x, e.g.,
$x = "$arr['x']";
Parse error: syntax error, unexpected '' (T_ENCAPSED_AND_WHITESPACE), expecting '-' or identifier (T_STRING) or variable (T_VARIABLE) or number (T_NUM_STRING)
$result = 5; // 2nd item of split - loaded from file line (ok)
and then compare
if ($result == $x)
{
echo "ok";
}
or can't this be done?
PS: minimal example - that's why i removed loading from file and split
Because you have expressions in your variables you will either need to write an expression parser or use eval. This is how you can make it work with eval:
$vars = array("\$arr['x'];5", "\$a;53", "\$b - \$a;27");
$arr['x'] = 5;
$a = 54;
$b = 81;
foreach ($vars as $var) {
list($x, $result) = explode(';', $var);
if (eval("return $result == $x;")) {
echo "$x = $result\n";
}
else {
echo "$x != $result\n";
}
}
Output
$arr['x'] = 5
$a != 53
$b - $a = 27
Demo on 3v4l.org
Why you have written enclosed $arr['x'] with double quotation marks like this
$x = "$arr['x']";
Remove quotation marks from this statement and make it like this
$x = $arr['x'];
Let's say I want to check for a couple of different parameters, and then fall back to a default value, is there a way to do it without ugly and verbose writing of isset()?
For example in JS we can do:
var someVariable = otherVar || anotherVar || 'fallback here';
The equivalent in PHP would be something like:
$someVariable = (isset($otherVar) ? $otherVar : (isset($anotherVar) ? $anotherVar : 'fallback here'));
which is obviously a mess and horrible to read.
Lots of solutions exist for single fallbacks, i.e.:
$someVariable = $otherVar ?: 'fallback here';
but that doesn't help me with requiring more than one in the line of checks.
Given that I am only interested in whether or not the value is set or truth-y (i.e. I am happy for 1 to be accepted as the used value, and for 0/false/null to be skipped and for the next parameter in the chain to be used), what is the best way to avoid the undefined index warning?
In reality, I would be doing this on arrays in most cases, but not all, and it's probably that they will be different arrays. I may want to use $_POST for the first, then check $_GET under a different key, and then fall back to a default string for example.
Ignoring PHP warnings and notices is not a good idea at all.
But just for the experiment, I can suggest you the error control operator #.
PHP supports one error control operator: the at sign (#). When prepended to an expression in PHP, any error messages that might be generated by that expression will be ignored.
$someVariable = #$otherVar ? #$var : 'fallback here';
echo $someVariable;
// output: fallback here
http://php.net/manual/en/language.operators.errorcontrol.php
You can chain ?: but you'll still need to suppress errors with #.
For example, the following will work similarly to your JavaScript example:
$foo = #$bar ?: #$baz ?: #$qux ?: "I give up";
It's the equivalent of multiple "single fallbacks":
$foo = (#$bar ?: (#$baz ?: (#$qux ?: "I give up")));
Be careful though, ?: only checks for truthyness. There are scenarios where isset() and truthyness do not agree. Additionally, ?: fallback functionality was introduced in PHP 5.3.
If you only care about nullness and have PHP 7 available, it introduced a null coalescing operator.
This is ambiguous and it is deprecated...
$something = $a ? $b : $c ?: $d;
So, you have 2 alternatives for grouping:
$something = $a ? $b : ($c ?: $d); // version 1
$something = ($a ? $b : $c) ?: $d; // version 2
Which one is correct? Let's test this...
$posibilities = [TRUE, FALSE, NULL, [], new stdClass()];
$v1_is_correct = TRUE;
$v2_is_correct = TRUE;
foreach ($posibilities as $a) {
foreach ($posibilities as $b) {
foreach ($posibilities as $c) {
foreach ($posibilities as $d) {
$original = (int)($a ? $b : $c ?: $d);
$v1 = (int)($a ? $b : ($c ?: $d));
$v2 = (int)(($a ? $b : $c) ?: $d);
$v1_is_correct = $v1_is_correct && ($original === $v1);
$v2_is_correct = $v2_is_correct && ($original === $v2);
print "ORIG: $original - V1: $v1 - V2: $v2 \n";
}
}
}
}
print "\n";
$v1_is_correct ? print "V1 is correct \n" : NULL;
$v2_is_correct ? print "V2 is correct \n" : NULL;
Result: V2 is correct.
$a ? $b : $c ?: $d
is equivalent to...
($a ? $b : $c) ?: $d
I'd like a way to simplify an if/else statement that concatenates two values together, but also checks for null values before using the variables.
For example:
if (isset($A,$B)) {
$C = $A . $B;
}
elseif(isset($A)) {
$C = $A;
}
elseif(isset($B)) {
$C = $B;
}
Before concatenating $A with $B I need to make sure neither are NULL. If they both contain a value, then I want to assign the concatenation to the variable $C. If either value is null, then I want just one value assigned to $C.
The above works fine when I only have two variables, but what if a third variable $D were added and I needed to concatenate into $C and still check for nulls. Then I would need to check first for ABD, then AB, then BD, then A, then B, then D. It will get really unruly.
So how can I simplify the code and allow for more variables to be added in the future if necessary?
How about the following:
<?php
$a=NULL;
$b="hello ";
$c=NULL;
$d="world\n";
$all = implode(array($a,$b,$c,$d));
echo $all;
?>
This prints
hello world
without any errors. It is an implementation of the comment that #wor10ck made - but he didn't seem to follow up with a full answer / example and I thought his suggestion was worth fleshing out.
EDIT for people who don't read comments - #Keven ended up using
$result = implode(array_filter($array));
which is a nice robust way to remove the NULL elements in the array.
$C = (isset($A) ? $A : '') . (isset($B) ? $B : '') . (isset($D) ? $D : '');
You might find this usefull
$C = "";
$C .= (isset($A) ? $A : "").(isset($B) ? $B : "");
The question mark operator returns the left part before the : symbol if the statement is true, and right if false. Hoever i think that nesting statements in if block is more optimised.
<?php
// I assume $res is the variable containing the result of the concatenations
$res = '';
if(isset($a))
$res .= $a;
if(isset($b))
$res .= $b;
if(isset($c))
$res .= $c;
// ...
$A = 'a';
$B = 'b';
$C = '';
$C .= isset($A) ? $A : '';
$C .= isset($B) ? $B : '';
$C .= isset($D) ? $D : '';
echo $C;
I have a really quick question for you:
I read data from an Excel sheet and want to transform it into an assoc array. But sometimes there are no values given in some cells. So if this occurs I want to set the value of the array to 0.
right now I do it like that with the ternary operator and I'm glad I discovered that today:
(isset($excel->sheet[0]['cells'][$row][$value]) ? $excel->sheet[0]['cells'][$row][$value] : 0)
Is there a whay to shorten the repitition in this case? It works but it ain't that pretty :(
Although this is not recommended, I would go the following way (PHP 5.3):
(#$excel->sheet[0]['cells'][$row][$value] ? : 0);
Error suppression operator is a mess, but in this case the only thing you suppress is a well-known notice about undefined variable.
Another option (as stated by Álvaro G. Vicario) could be a simple cast to int (as NULL casts to 0):
(int)#$excel->sheet[0]['cells'][$row][$value];
Another option is making a function to check the existence of such variable – maybe it's a little over-engineering, overkill or just too much –:
function iset($array, $output) {
$args = func_get_args();
$val = $array;
for ($i = 1; $i < count($args) - 1; $i++) {
if (!isset($val[func_get_arg($i)])) {
return func_get_arg(func_num_args() - 1);
}
$val = $val[func_get_arg($i)];
}
return $val;
}
Then use the function like this:
$var = iset($excel->sheet, 0, 'cells', $row, $value, "DEFAULT_VALUE");
Simple question, simple code. This works:
$x = &$_SESSION['foo'];
This does not:
$x = (isset($_SESSION['foo']))?&$_SESSION['foo']:false;
It throws PHP Parse error: syntax error, unexpected '&'. Is it just not possible to pass by reference while using the conditional operator, and why not? Also happens if there's a space between the ? and &.
In the very simply case, this expression, which is illegal;
$c = condition ? &$a : &$b; // Syntax error
can be written like this:
$c = &${ condition ? 'a' : 'b' };
In your specific case, since you're not assigning by reference if the condition is false, a better option seems to be:
$x = isset($_SESSION['foo']) ? $x = &$_SESSION['foo'] : false;
Simple answer: no. You'll have to take the long way around with if/else. It would also be rare and possibly confusing to have a reference one time, and a value the next. I would find this more intuitive, but then again I don't know your code of course:
if(!isset($_SESSION['foo'])) $_SESSION['foo'] = false;
$x = &$_SESSION['foo'];
As to why: no idea, probably it has to with at which point the parser considers something to be an copy of value or creation of a reference, which in this way cannot be determined at the point of parsing.
Let's try:
$x =& true?$y:$x;
Parse error: syntax error, unexpected '?', expecting T_PAAMAYIM_NEKUDOTAYIM in...
$x = true?&$y:&$x;
Parse error: syntax error, unexpected '&' in...
So, you see, it doesn't even parse. Wikken is probably right as to why it's not allowed.
You can get around this with a function:
function &ternaryRef($cond, &$iftrue, &$iffalse=NULL) {
if ($cond)
return $iftrue;
else
return $iffalse;
}
$x = 4;
$a = &ternaryRef(true, $x);
xdebug_debug_zval('a');
$b = &ternaryRef(false, $x);
xdebug_debug_zval('b');
gives:
a: (refcount=2, is_ref=1),int 4
b: (refcount=1, is_ref=0),null
Unfortunately, you can't.
$x=false;
if (isset($_SESSION['foo']))
$x=&$_SESSION['foo'];
The commentary on this bug report might shed some light on the issue:
http://bugs.php.net/bug.php?id=53117.
In essence, the two problems with trying to assign a reference from the result of a ternary operator are:
Expressions can't yield references, and
$x = (expression) is not a reference assignment, even if (expression) is a reference (which it isn't; see point 1).