How can I create a new operator in PHP? - php

I see myself doing the following code for default assigment all the type on PHP
$variable = $variable ? $variable : 'default value';
I know that with 5.3 I can do
$variable = $variable ?: 'default value';
I would like to further simplify it by being able to just do
$variable ?= 'default value';
and have the variable reassigned in case it evaluates to false. Is it possible to create that assignment? Do I have to compile my own version of php to do that?

You cannot create new operators in PHP without changing the PHP source.
And you don't want to change it, trust me. Sure, it'd be easy enough - PHP is open source and uses a straightforward LALR(1) parser which you could easily modify - but that would make your code incompatible with the standard PHP implementation. You would thus very much restrict who can run the code - which will probably be nobody apart from you, as nobody else will care to modify their PHP engine just to run your code.
Update: I wrote a small tutorial on how to add new syntax (like operators) to PHP: https://www.npopov.com/2012/07/27/How-to-add-new-syntactic-features-to-PHP.html

In PHP, you can't create operators or overload the existing operators, such as =.
You can check the package Operator, but, your code will not be runnable withoud it.

You cannot do this in PHP,not with this syntax.
<?
$test = array("3 is 5", "3 is not 5");
$r = $teste [+( 3 != 5)];
echo $r; //return "3 is not 5"
?>

It seems that this is the one example that comes up the most when wondering if it's possible to create new operations. I personally think that ?= would be quite handy.
Since creating new operators would involve creating your own PHP version, and may not very useful for others if you decide to package your code, you can instead easily create a function to emulate the same effect.
/**
* Global function to simplify the process of
* checking to see if a value equates to true
* and setting it to a new value if not.
*
* #param mixed $var the original variable to
* check and see if it equates to true/false
* #param mixed $default the default value to
* replace the variable if it equates to false
*
* #return mixed returns the variable for
* either further processing or assignment.
*/
function _d( &$var, $default ) {
return $var = $var ?: $default;
}
You can then call the function, assign it to another variable as required, or even nest them as required to assign default values down a hierarchy of variables.
_d( $variable, 'default value' );
// $variable = $variable ?: 'default value';
$variable1 = _d( $variable, 'default value' ) . 's';
// $variable1 = ( $variable = $variable ?: 'default value' ) . 's';
_d( $variable, _d( $variable1, 'default value' ) );
// $variable = $variable ?: ( $variable1 = $variable1 ?: 'default value' );
EDIT:
As a side note, the function will also assign the default value to the variable even if it has not yet been defined.
You can create a similar function, or modify the function above to the following, if you would prefer to only update the variable if it is not defined.
return $var = isset( $var ) ? $var : $default;}

its simple, php is a php preprocessor, simply preprocess your php file containing your operator to translate all operators you want into it's underlying representation.
otherwise sadly php is not perl/lisp so you can't simply extend the language at runtime to that extent

You could use a function:
<?php
function defvar(&$var) {
if (empty($var)) { $var = 'default value'; }
}
// testing
$set = 'test';
defvar($set);
echo $set;
defvar($notset);
echo $notset;
?>
Output:
test
default value
Or if you prefer assignment:
<?php
function setdefvar($var) {
if (empty($var)) { return 'default value'; }
else { return $var; }
}
// testing
$set = 'test';
$set = setdefvar($set);
echo $set;
$notset = setdefvar($notset);
echo $notset;
?>
Output:
test
default value

Related

How to check if variable was passed by reference in PHP

Straightforward:
I want to write some code which tells if a variable was passed by reference or not.
For example:
<?php
function isReference($variable) {
//return TRUE if &$something was passed
//return FALSE if $something was passed
}
$text = 'Anything';
$a = isReference(&$text); //return TRUE
$b = isReference($test); //return FALSE
?>
For those who are curious - why do I need it?
Firstly I do not like to leave problems unsolved.
Secondly, I am currently enhancing by skills by writing an extension to mysqli, which would prepare statements similar to how PDO does. If anybody knows the difference between bindParam and bindValue in PDO, they know that it's a workaround of this question. I can just make two functions, but I wonder if it's possible with one.
Thanks in advance.
Here's a way to do it without using the debug_zval_dump function:
function isReference($variable) {
$variable = array($variable);
$arg = func_get_arg(0);
$isRef = isset($arg[0]) && $arg === array($variable[0]);
$variable = $variable[0];
return $isRef;
}
Note: there is only a single case when this will not work:
$text = array(&$text); // although i don't see why such a structure could be used
isReference($text); // will wrongly return false
Obviously you can bypass this limitation by using a random unique key (instead of 0).
You can use debug_zval_dump to dump a string representation of an internal zend value to output:
function isRef(&$val) {
ob_start();
debug_zval_dump(&$val);
$ret = ob_get_clean();
preg_match('~refcount\((\d+)\)~', $ret, $matches);
return $matches[1] - 4;
}
$var1 = 'Var1';
$var2 = &$var1; // passed by ref
if(isRef($var2)) echo 'Passed by ref';
But be aware of PHP - 5.4.
Simply checking for the default value seems to work fine in my tests. Obviously it wont work if $t is already set to 'x' but you could change the default value to something totally unlikely to workaround this:
function test(&$t='x'){
if($t!='x') $t = 2;
}
test(); echo $t; //outputs: null
test($t); echo $t; //outputs: 2

PHP help - only need a simple explanation

Alright, I'm trying to understand how this PHP code works.
<?php
$test = "success";
$primary = "test";
$id = ${$primary};
echo $id;
?>
I know the output is "success" but I don't understand how it works.
What i understand so far:
test variable has the string "success",
primary variable has the string "test",
'id' variable has the string of the first variable in the list (the test variable),
print the string in the 'id' variable.
I'm confused because i don't know what the primary variable is doing in the braces within the id variable.
A simple explanation would be appreciated.
This is a concept called variable variables.
It means that at runtime, if multiple variable indicators $ are present, PHP will attempt to associate them in a cascading manner.
For example, take the following:
$a = "b";
$b = "c";
$c = "d";
echo $$$a;
PHP will systematically go through the echo statement to determine what the actual value is, as such:
$$$a is equivalent to $$("b") (because $a is "b")
...which is equivalent to $("c") (because $b is "c")
...which is finally equivalent to "d"
In your example, you're given a variable assignment to something that, in essence, is like ${$a}. In PHP, braces are used to isolate variables within strings, but can be used on their own to denote a variable explicitly, so ${$a} is exactly equivalent to $$a in this case.
$id = ${$primary};
try to parse from right to left $primary = 'test'
so ${$primary} is now $test
so equation becomes $id = $test;
$id = $test = success
Know more about variables variables on the link provided by other users
This is a variable variable.
$test = "success";
$primary = "test";
//${$primary} means $test here, because value of $primary is "test".
//It is equal to $$primary
$id = ${$primary};
echo $id; //Prints "success"
http://php.net/manual/en/language.variables.variable.php

how to store isset condition php to avoid repetition

my code:
if (isset($dayMarks[$res['resId']][$dDate])) {
$var=$dayMarks[$res['resId']][$dDate];
echo $var;
}
note that the isset condition is identical to the value assigned to $var, which creates a pretty ugly code.
How is it possible to assign the condition to $var without repeating it?
(in javascript, I'd write if (var=$dayMarks[$re...) )
This is a common problem in PHP where including files can create uncertainty about variables.
There are a two approaches that work well for me.
Default Assignment
With default assignment the $var variable will be given a default value when the key doesn't exist.
$var = isset($dayMarks[$res['resId']][$dDate]) ? $dayMarks[$res['resId']][$dDate] : false;
After this code can assume that $var will always contain a valid value.
Default Merger
My preferred method is to always declare a default array that contains all the required values, and their defaults. Using the False value to mark any keys that might be missing a value (assuming that key holds another value type besides boolean).
$default = array(
'date'=>false,
'name'=>'John Doe'
);
$dayMarks[$res['resId']] = array_merge($default, $dayMarks[$res['resId']]);
This will ensure that the required keys for that variable exist, and hold at least a default value.
You can now test if the date exists.
if($dayMarks[$res['resId']]['date'] !== false)
{
// has a date value
}
While this might not work exactly for your array. Since it looks like it's a table structure. There is a benefit to switching to named key/value pairs. As this allows you to easily assign default values to that array.
EDIT:
The actual question was if it was possible to reproduce the JavaScript code.
if (var=$dayMarks[$re...)
Yes, this can be done by using a helper function.
NOTE: This trick should only be used on non-boolean types.
function _isset($arr,$key)
{
return isset($arr[$key]) ? $arr[$key] : false;
}
$a = array('zzzz'=>'hello');
if(($b = _isset($a,'test')) !== false)
{
echo $b;
}
if(($c = _isset($a,'zzzz')) !== false)
{
echo $c;
}
See above code here
$isset = isset(...); //save the value
if ($isset) { .... }; // reuse the value
...
if ($isset) { ... }; // reuse it yet again
The only thing you can do is store $res['resId'][$dDate].
$var = $res['resId'][$dDate];
if( isset($dayMarks[$var]) ) {
$var = $dayMarks[$var];
echo $var;
}
If you only want to assign a variable processing simply, you can also write this as:
$var = $dayMarks[$res['resId']][$dDate]);
if (!isset($var)) unset($var);

Proper way to declare multiple vars in PHP

I've been coding personal scripts for years in PHP and get used to turn off Error display. I'm about to release some of these scripts and would like to do it the proper way.
The only reason why I turn off error display is to avoid having to test every single var, prior using it, thanks to isset().
So, here is my question:
Is there a better way to declare multiple vars than this ?
<?php
// at the begining of my main file
if (!isset($foo)) ($foo = '');
if (!isset($bar)) ($bar = '');
if (!isset($ping)) ($ping = '');
if (!isset($pong)) ($pong = '');
// etc. for every single var
?>
Something like this for instance :
<?php
var $foo, $bar, $ping, $pong;
?>
<?php
$foo = $bar = $ping = $pong = '';
?>
If it's your script and you know which variables where you use, why you want spend recourses to check if the variable was declared before?
I posted this in a comment earlier, but someone suggested I submit it as an answer.
The shortest and simplest way I can think of, is to do:
$foo = $bar = $ping = $pong = '';
I often prefer to set things to false, instead of an empty string, so that you can always do checks in the future with === false, but that is just a preference and depends on how you are using these variables and for what.
Your if() with isset() attempt is the proper way of doing that!
But you can write it a little bit shorter/more readable, using the Ternary Operator:
$foo = isset($foo) ? $foo : '';
The first $foo will be set to the value after the ? when the condition after the = is true, else it will be set to the value after the :. The condition (between = and ? ) will always be casted as boolean.
Since PHP 5.3 you can write it even shorter:
$foo = isset($foo) ?: '';
This will set $foo to TRUE or FALSE (depending on what isset() returns), as pointed by #Decent Dabbler in the comments. Removing isset() will set it to '' but it will also throw an undefined variable notice (not in production though).
Since PHP 7 you can use a null coalesce operator:
$foo = $foo ?? '';
This won't throw any error, but it will evaluate as TRUE if $foo exists and is empty, as opposed to the shorthand ternary operator, that will evaluate as FALSE if the variable is empty.
A somewhat round-about way of doing this is if you put the name of your variables in an array, and then loop them with a Ternary Operator, similar to powtac's answer.
$vars = array('foo', 'bar', 'ping', 'pong');
$defaultVar = '';
foreach($vars as $var)
{
$$var = isset($$var) ? $$var : $defaultVar;
}
As mentioned in other answers, since version 5.3, PHP allows you to write the above code as follows:
$vars = array('foo', 'bar', 'ping', 'pong');
$defaultVar = '';
foreach($vars as $var)
{
$$var = isset($$var) ?: $defaultVar;
}
Note the changed Ternary Operator.
In OOP you can use this approach:
protected $password, $full_name, $email;
For non-OOP you declare them just in code they will be Undefined if you didn't assign any value to them:
$foo; $bar; $baz;
$set_foo = (isset($foo)) ? $foo : $foo = 'Foo';
echo $set_foo;
Why not just set them?
<?php
$foo = '';
$bar = '';
//etc
?>
If you're trying to preserve the value in them, then yes that's the correct way in general. Note that you don't need the second pair of brackets in your statements:
if (!isset($foo)) $foo = '';
is enough.
To fix the issue of
<?php
$foo = $bar = $ping = $pong = '';
?>
throwing
Notice: Undefined variable: ...
<?php
#$foo = $bar = $ping = $pong = '';
?>
It will not fix it but it will not be shown nd will not stop the script from parsing.

Function to set default value of associative array if the key is not present

Is there a function in PHP to set default value of a variable if it is not set ?
Some inbuilt function to replace something like:
$myFruit = isset($_REQUEST['myfruit']) ? $_REQUEST['myfruit'] : "apple" ;
PHP kind of has an operator for this (since 5.3 I think) which would compress your example to:
$myFruit = $_REQUEST['myfruit'] ?: "apple";
However, I say "kind of" because it only tests if the first operand evaluates to false, and won't suppress notices if it isn't set. So if (as in your example) it might not be set then your original code is best.
The function analogous to dictionary.get is trivial:
function dget($dict, $key, $default) {
return isset($dict[$key]) ? $dict[$key] : $default;
}
For clarity, I'd still use your original code.
Edit: The userland implementation #2 of ifsetor() at http://wiki.php.net/rfc/ifsetor is a bit neater than the above function and works with non-arrays too, but has the same caveat that the default expression will always be evaluated even if it's not used:
function ifsetor(&$variable, $default = null) {
if (isset($variable)) {
$tmp = $variable;
} else {
$tmp = $default;
}
return $tmp;
}
As far as i know there exists nothing like this in PHP.
You may implement something like this yourself like
$myVar = "Using a variable as a default value!";
function myFunction($myArgument=null) {
if($myArgument===null)
$myArgument = $GLOBALS["myVar"];
echo $myArgument;
}
// Outputs "Hello World!":
myFunction("Hello World!");
// Outputs "Using a variable as a default value!":
myFunction();
// Outputs the same again:
myFunction(null);
// Outputs "Changing the variable affects the function!":
$myVar = "Changing the variable affects the function!";
myFunction();
You could also create a class implementing the ArrayAccess, which you pass 2 arrays during construction ($_REQUEST and an array with defaults) and make it choose the default value transparently.
Btw., relying on $_REQUEST is not a wise idea. See the manual on $_REQUEST for further information.
Instead of testing, if a key not exists and then return a default value, you can also fill your array with this values, before accessing it.
$expectedKeys = array('myfruit');
$requestData = array_merge (
array_combine(
$expectedKeys,
array_fill(0, count($expectedKeys), null)),
$_REQUEST);
$postData is now an array with all keys you expect (specified by $expectedKeys), but any entry, that is missing in $_REQUEST is null.
$myFruit = $requestData['myfruit'];
if (is_null($myFruit)) {
// Value not exists
}
But I also recommend to just stay with the ternary operator ?:.
There is a function called ife() in the CakePHP framework, you can find it here http://api13.cakephp.org/view_source/basics.php/, it is the last function!
You can use it like this:
echo ife($variable, $variable, 'default');

Categories