Deducing PHP Closure parameters - php

Is there any chance that I can deduce PHP Closure parameters type information? Consider this example:
<?php
$foo = function(array $args)
{
echo $args['a'] . ' ' . $args['b'];
};
$bar = function($a, $b)
{
echo $a . ' ' . $b;
};
$closure = /* some condition */ $foo : $bar;
if(/* $closure accepts array? */)
{
call_user_func($closure, ['a' => 5, 'b' => 10]);
}
else
{
call_user_func($closure, 5, 10);
}
?>
I want to leave some freedom for user so he or she could decide which way is better to define a Closure that will be registered in my dispatcher - will it accept parameters in associative array or directly as Closure parameters. So, dispatcher need to deduce parameters of the passed Closure to determine which way should it call this Closure. Any ideas?

Use reflection, if you need to make decisions, based on code structure. In your case ReflectionFunction and ReflectionParameter are your friends.
<?php
header('Content-Type: text/plain; charset=utf-8');
$func = function($a, $b){ echo implode(' ', func_get_args()); };
$closure = $func;
$reflection = new ReflectionFunction($closure);
$arguments = $reflection->getParameters();
if($arguments && $arguments[0]->isArray()){
echo 'Giving array. Result: ';
call_user_func($closure, ['a' => 5, 'b' => 10]);
} else {
echo 'Giving individuals. Result: ';
call_user_func($closure, 5, 10);
}
?>
Output:
Giving individuals. Result: 5 10
Change definition to test:
$func = function(array $a){ echo implode(' ', $a); };
Output:
Giving array. Result: 5 10

It would be much easier to have your function be able to accept different types of input.
For instance, in this case:
$foo = function() {
$args = func_get_args();
if( is_array($args[0])) $args = $args[0];
echo $args[0]." ".$args[1];
}

Related

Issue sharing variable between two functions | PHP [duplicate]

Is it possible to have a function with two returns like this:
function test($testvar)
{
// Do something
return $var1;
return $var2;
}
If so, how would I be able to get each return separately?
Technically, you can't return more than one value. However, there are multiple ways to work around that limitation. The way that acts most like returning multiple values, is with the list keyword:
function getXYZ()
{
return array(4,5,6);
}
list($x,$y,$z) = getXYZ();
// Afterwards: $x == 4 && $y == 5 && $z == 6
// (This will hold for all samples unless otherwise noted)
Technically, you're returning an array and using list to store the elements of that array in different values instead of storing the actual array. Using this technique will make it feel most like returning multiple values.
The list solution is a rather php-specific one. There are a few languages with similar structures, but more languages that don't. There's another way that's commonly used to "return" multiple values and it's available in just about every language (in one way or another). However, this method will look quite different so may need some getting used to.
// note that I named the arguments $a, $b and $c to show that
// they don't need to be named $x, $y and $z
function getXYZ(&$a, &$b, &$c)
{
$a = 4;
$b = 5;
$c = 6;
}
getXYZ($x, $y, $z);
This technique is also used in some functions defined by php itself (e.g. $count in str_replace, $matches in preg_match). This might feel quite different from returning multiple values, but it is worth at least knowing about.
A third method is to use an object to hold the different values you need. This is more typing, so it's not used quite as often as the two methods above. It may make sense to use this, though, when using the same set of variables in a number of places (or of course, working in a language that doesn't support the above methods or allows you to do this without extra typing).
class MyXYZ
{
public $x;
public $y;
public $z;
}
function getXYZ()
{
$out = new MyXYZ();
$out->x = 4;
$out->y = 5;
$out->z = 6;
return $out;
}
$xyz = getXYZ();
$x = $xyz->x;
$y = $xyz->y;
$z = $xyz->z;
The above methods sum up the main ways of returning multiple values from a function. However, there are variations on these methods. The most interesting variations to look at, are those in which you are actually returning an array, simply because there's so much you can do with arrays in PHP.
First, we can simply return an array and not treat it as anything but an array:
function getXYZ()
{
return array(1,2,3);
}
$array = getXYZ();
$x = $array[0];
$y = $array[1];
$z = $array[2];
The most interesting part about the code above is that the code inside the function is the same as in the very first example I provided; only the code calling the function changed. This means that it's up to the one calling the function how to treat the result the function returns.
Alternatively, one could use an associative array:
function getXYZ()
{
return array('x' => 4,
'y' => 5,
'z' => 6);
}
$array = getXYZ();
$x = $array['x'];
$y = $array['y'];
$z = $array['z'];
Php does have the compact function that allows you to do same as above but while writing less code. (Well, the sample won't have less code, but a real world application probably would.) However, I think the amount of typing saving is minimal and it makes the code harder to read, so I wouldn't do it myself. Nevertheless, here's a sample:
function getXYZ()
{
$x = 4;
$y = 5;
$z = 6;
return compact('x', 'y', 'z');
}
$array = getXYZ();
$x = $array['x'];
$y = $array['y'];
$z = $array['z'];
It should be noted that while compact does have a counterpart in extract that could be used in the calling code here, but since it's a bad idea to use it (especially for something as simple as this) I won't even give a sample for it. The problem is that it will do "magic" and create variables for you, while you can't see which variables are created without going to other parts of the code.
Finally, I would like to mention that list doesn't really play well with associative array. The following will do what you expect:
function getXYZ()
{
return array('x' => 4,
'y' => 5,
'z' => 6);
}
$array = getXYZ();
list($x, $y, $z) = getXYZ();
However, the following will do something different:
function getXYZ()
{
return array('x' => 4,
'z' => 6,
'y' => 5);
}
$array = getXYZ();
list($x, $y, $z) = getXYZ();
// Pay attention: $y == 6 && $z == 5
If you used list with an associative array, and someone else has to change the code in the called function in the future (which may happen just about any situation) it may suddenly break, so I would recommend against combining list with associative arrays.
There is no way of returning 2 variables. Although, you can propagate an array and return it; create a conditional to return a dynamic variable, etc.
For instance, this function would return $var2
function wtf($blahblah = true) {
$var1 = "ONe";
$var2 = "tWo";
if($blahblah === true) {
return $var2;
}
return $var1;
}
In application:
echo wtf();
//would echo: tWo
echo wtf("not true, this is false");
//would echo: ONe
If you wanted them both, you could modify the function a bit
function wtf($blahblah = true) {
$var1 = "ONe";
$var2 = "tWo";
if($blahblah === true) {
return $var2;
}
if($blahblah == "both") {
return array($var1, $var2);
}
return $var1;
}
echo wtf("both")[0]
//would echo: ONe
echo wtf("both")[1]
//would echo: tWo
list($first, $second) = wtf("both")
// value of $first would be $var1, value of $second would be $var2
In your example, the second return will never happen - the first return is the last thing PHP will run. If you need to return multiple values, return an array:
function test($testvar) {
return array($var1, $var2);
}
$result = test($testvar);
echo $result[0]; // $var1
echo $result[1]; // $var2
Since PHP 7.1 we have proper destructuring for lists.
Thereby you can do things like this:
$test = [1, 2, 3, 4];
[$a, $b, $c, $d] = $test;
echo($a);
> 1
echo($d);
> 4
In a function this would look like this:
function multiple_return() {
return ['this', 'is', 'a', 'test'];
}
[$first, $second, $third, $fourth] = multiple_return();
echo($first);
> this
echo($fourth);
> test
Destructuring is a very powerful tool. It's capable of destructuring key=>value pairs as well:
["a" => $a, "b" => $b, "c" => $c] = ["a" => 1, "b" => 2, "c" => 3];
Take a look at the new feature page for PHP 7.1:
New features
In PHP 5.5 there is also a new concept: generators, where you can yield multiple values from a function:
function hasMultipleValues() {
yield "value1";
yield "value2";
}
$values = hasMultipleValues();
foreach ($values as $val) {
// $val will first be "value1" then "value2"
}
Or you can pass by reference:
function byRef($x, &$a, &$b)
{
$a = 10 * $x;
$b = 100 * $x;
}
$a = 0;
$b = 0;
byRef(10, $a, $b);
echo $a . "\n";
echo $b;
This would output
100
1000
For PHP 7.1.0 onwards, you can use the new syntax (instead of the list function):
/**
* #return array [foo, bar]
*/
function getFooAndBar(): array {
return ['foo', 'bar'];
}
[$foo, $bar] = getFooAndBar();
print 'Hello '. $foo . ' and ' . $bar;
It's OK for me if you want to return 2-3 variables, otherwise you should use an object with the desired properties.
I know that I am pretty late, but there is a nice and simple solution for this problem.
It's possible to return multiple values at once using destructuring.
function test()
{
return [ 'model' => 'someValue' , 'data' => 'someothervalue'];
}
Now you can use this
$result = test();
extract($result);
extract creates a variable for each member in the array, named after that member. You can therefore now access $model and $data
You can return multiple arrays and scalars from a function
function x()
{
$a=array("a","b","c");
$b=array("e","f");
return array('x',$a,$b);
}
list ($m,$n,$o)=x();
echo $m."\n";
print_r($n);
print_r($o);
Its not possible have two return statement. However it doesn't throw error but when function is called you will receive only first return statement value.
We can use return of array to get multiple values in return. For Example:
function test($testvar)
{
// do something
//just assigning a string for example, we can assign any operation result
$var1 = "result1";
$var2 = "result2";
return array('value1' => $var1, 'value2' => $var2);
}
Best Practice is to put your returned variables into array and then use list() to assign array values to variables.
<?php
function add_subt($val1, $val2) {
$add = $val1 + $val2;
$subt = $val1 - $val2;
return array($add, $subt);
}
list($add_result, $subt_result) = add_subt(20, 7);
echo "Add: " . $add_result . '<br />';
echo "Subtract: " . $subt_result . '<br />';
?>
Functions, by definition, only return one value.
However, as you assumed, that value can be an array.
So you can certainly do something like:
<?PHP
function myfunc($a,$b){
return array('foo'=>$a,'bar'=>$b);
}
print_r(myfunc('baz','bork'));
That said, it's worth taking a moment and thinking about whatever you're trying to solve. While returning a complex result value (like an array, or an object) is perfectly valid, if you're thinking is that "I want to return two values", you might be designing poorly. Without more detail in your question, it's hard to say, but it never hurts to stop and think twice.
The answer that's given the green tick above is actually incorrect. You can return multiple values in PHP, if you return an array. See the following code for an example:
<?php
function small_numbers()
{
return array (0, 1, 2);
}
list ($zero, $one, $two) = small_numbers();
This code is actually copied from the following page on PHP's website: http://php.net/manual/en/functions.returning-values.php
I've also used the same sort of code many times myself, so can confirm that it's good and that it works.
Yes, you can use an object :-)
But the simplest way is to return an array:
return array('value1', 'value2', 'value3', '...');
I have implement like this for multiple return value PHP function. be nice with your code. thank you.
<?php
function multi_retun($aa)
{
return array(1,3,$aa);
}
list($one,$two,$three)=multi_retun(55);
echo $one;
echo $two;
echo $three;
?>
PHP 7.1 Update
Return an array.
function test($testvar)
{
// Do something
return [$var1, $var2];
}
then use that like below:
[$value1, $value2] = test($testvar);
Functions in PHP can return only one variable. you could use variables with global scope, you can return array, or you can pass variable by reference to the function and than change value,.. but all of that will decrease readability of your code.
I would suggest that you look into the classes.
Thought I would expand on a few of the responses from above....
class nameCheck{
public $name;
public function __construct(){
$this->name = $name;
}
function firstName(){
// If a name has been entered..
if(!empty($this->name)){
$name = $this->name;
$errflag = false;
// Return a array with both the name and errflag
return array($name, $errflag);
// If its empty..
}else if(empty($this->name)){
$errmsg = 'Please enter a name.';
$errflag = true;
// Return both the Error message and Flag
return array($errmsg, $errflag);
}
}
}
if($_POST['submit']){
$a = new nameCheck;
$a->name = $_POST['name'];
// Assign a list of variables from the firstName function
list($name, $err) = $a->firstName();
// Display the values..
echo 'Name: ' . $name;
echo 'Errflag: ' . $err;
}
?>
<form method="post" action="<?php $_SERVER['PHP_SELF']; ?>" >
<input name="name" />
<input type="submit" name="submit" value="submit" />
</form>
This will give you a input field and a submit button once submitted, if the name input field is empty it will return the error flag and a message. If the name field has a value it will return the value/name and a error flag of 0 for false = no errors.
Hope this helps!
Some might prefer returning multiple values as object:
function test() {
$object = new stdClass();
$object->x = 'value 1';
$object->y = 'value 2';
return $object;
}
And call it like this:
echo test()->x;
Or:
$test = test();
echo $test->y;
Yes and no. You can't return more than one variable / object, but as you suggest, you can put them into an array and return that.
There is no limit to the nesting of arrays, so you can just package them up that way to return.
You can always only return one variable which might be an array. But You can change global variables from inside the function. That is most of the time not very good style, but it works. In classes you usually change class varbiables from within functions without returning them.
The answer is no. When the parser reaches the first return statement, it will direct control back to the calling function - your second return statement will never be executed.
Add all variables in an array and then finally return the array.
function test($testvar)
{
// do something
return array("var1" => $var1, "var2" => #var2);
}
And then
$myTest = test($myTestVar);
//$myTest["var1"] and $myTest["var2"] will be usable
I think eliego has explained the answer clearly. But if you want to return both values, put them into a array and return it.
function test($testvar)
{
// do something
return array('var1'=>$var1,'var2'=>$var2);
//defining a key would be better some times
}
//to access return values
$returned_values = test($testvar);
echo $returned_values['var1'];
echo $returned_values['var2'];
<?php
function foo(){
$you = 5;
$me = 10;
return $you;
return $me;
}
echo foo();
//output is just 5 alone so we cant get second one it only retuns first one so better go with array
function goo(){
$you = 5;
$me = 10;
return $you_and_me = array($you,$me);
}
var_dump(goo()); // var_dump result is array(2) { [0]=> int(5) [1]=> int(10) } i think thats fine enough
?>
Languages which allow multiple returns usually just convert the multiple values into a data structure.
For example, in Python you can return multiple values. However, they're actually just being returned as one tuple.
So you can return multiple values in PHP by just creating a simple array and returning that.
You can get the values of two or more variables by setting them by reference:
function t(&$a, &$b) {
$a = 1;
$b = 2;
}
t($a, $b);
echo $a . ' ' . $b;
Output:
1 2
Does PHP still use "out parameters"? If so, you can use the syntax to modify one or more of the parameters going in to your function then. You would then be free to use the modified variable after your function returns.
$var1 = 0;
$var2 = 0;
function test($testvar, &$var1 , &$var2)
{
$var1 = 1;
$var2 = 2;
return;
}
test("", $var1, $var2);
// var1 = 1, var2 = 2
It's not a good way, but I think we can set two variables in a function at the same time.
This is the easiest way to do it:
public function selectAllUsersByRole($userRole, $selector) {
$this->userRole = $userLevel;
$this->selector = $selector;
$sql = "SELECT * FROM users WHERE role <= ? AND del_stat = 0";
$stm = $this->connect()->prepare($sql); // Connect function in Dbh connect to database file
$stm->execute([$this->userRole]); // This is PHP 7. Use array($this->userRole) for PHP 5
$usersIdArray = array();
$usersFNameArray = array();
$usersLNameArray = array();
if($stm->rowCount()) {
while($row = $stm->fetch()) {
array_push($usersIdArray, $row['id']);
array_push($usersFNameArray, $row['f_name']);
array_push($usersLNameArray, $row['l_name']);
// You can return only $row['id'] or f_name or ...
// I used the array because it's most used.
}
}
if($this->selector == 1) {
return $usersIdArray;
}elseif($this->selector == 2) {
return $usersFNameArray;
}elseif($this->selector == 3) {
return $usersLNameArray;
}
}
How can we call this function?
$idData = $selectAllUsers->selectAllUsersByLevel($userRole, 0);
print_r($idData);
$idFName = $selectAllUsers->selectAllUsersByLevel($userRole, 1);
print_r($idFname);
That's it. Very easy.

How to extract an associative array function argument AND pass a component of the array by reference in PHP?

For scalability purposes, I usually pass arguments to a function as an associative array (since the array is easily changed) and extract() in the function:
$a = 'a'; ....... $n = 'n';
$arg = array(
'a' => $a,
.
.
'n' => $n
);
function doStuff($arg) {
extract($arg);
// etc
}
But I have failed trying to do the same but passing a variable(s) component of $arg by reference. For example, to get the following result:
$a = 'x';
I can do this:
$a = 'a';
function doStuff(&$var) {
$var = 'x';
}
doStuff($a);
echo $a; // ---> echoes 'x'
How do you do this using the extract method? For example, the following echoes 'a', not 'x':
$a = 'a'; ....... $n = 'n';
$arg = array(
'a' => $a,
.
.
'n' => $n
);
function doStuff(&$arg) {
extract($arg);
$a = 'x';
}
doStuff($arg);
echo $a; // echoes 'a'
I have also tried this:
$arg = array(
'a' => &$a,
.
.
'n' => $n
);
Is it possible to use extract() here to make (in this case) $a echo as 'x' ?
I used the comment from Patrick Q for the correct answer:
$a = 'a'; ....... $n = 'n';
$arg = array(
'a' => &$a,
.
.
'n' => $n
);
function doStuff($arg) {
extract($arg, EXTR_REFS);
$a = 'x';
}
doStuff($arg);
echo $a; // echoes 'x'
As you are passing the $arg array by reference it is the $arg array that has to be changed to reflect this change out of the function scope, so I think you need to use combine or build the $arg back any other way with the changed values:
function doStuff(&$arg) {
extract($arg);
$a = 'x';
$arg = combine(...);
// OR
$arg = ['a' => $a];
}
To see it running:
http://sandbox.onlinephpfunctions.com/code/70b4b5e7d90b829588aa0fd0b3caf621fa1b5ed3

call_user_func_array vs ReflectionMethod

I was wondering about what the best practices are when it comes to call a class method using the above functions to fill up a method call dynamically using an array!
What advantages and disadvantages do I have? I mean, it seems the RefelectionMethod + invokeArgs option is up to 40% faster than the call_user_funcion in certain conditions… but do I miss something?
thanks.
As requested i will add a little benchmark of my scenario where i needed refereces to be passed... i know its a very specific case and that this is not stricly related to the question above!
class foo { public function bar(&$a, &$b, &$c) { /* */ } }
$t1 = microtime(true);
$arr = array(1,2,3);
$foo = new foo;
$rfl = new ReflectionMethod('foo', 'bar');
for ($i=0; $i < 10000; ++$i)
{
$rfl->invokeArgs($foo, $arr);
}
$t2 = microtime(true);
echo sprintf("\nElapsed reflectionmethod : %f", $t2 - $t1);
$t1 = microtime(true);
$arr = array(1,2,3);
$foo = new foo;
for ($i=0; $i < 10000; ++$i)
{
foreach( $arr as $k => $v ) $ref[$k] = &$arr[$k];
call_user_func_array( array($foo, 'bar'), $arr);
}
$t2 = microtime(true);
echo sprintf("\nElapsed calluserfuncarray : %f", $t2 - $t1);
the result
Elapsed reflectionmethod : 0.025099
Elapsed calluserfuncarray : 0.051189
I really would just like to know when its better to use one versus the other, and why! its not strictly related to speed though!
Not sure where you got your test results but RefelectionMethod + invokeArgs option is up to 40% faster than the call_user_funcion seems far fetched it can only be possible with single instance multiple invoke
Simple Benchmark
set_time_limit(0);
echo "<pre>";
class Foo {
public function bar($arg1, $arg2) {
}
}
$globalRefection = new ReflectionMethod('Foo', 'bar');
$globalFoo = new Foo();
// Using call_user_func_array
function m1($args) {
$foo = new Foo();
call_user_func_array(array($foo,"bar"), $args);
}
// Using ReflectionMethod:invoke
function m2($args) {
$foo = new ReflectionMethod('Foo', 'bar');
$foo->invoke(new Foo(), $args[0], $args[1]);
}
// Using ReflectionMethod:invokeArgs
function m3($args) {
$foo = new ReflectionMethod('Foo', 'bar');
$foo->invokeArgs(new Foo(), $args);
}
// Using Global Reflection
function m4($args) {
global $globalRefection;
$globalRefection->invokeArgs(new Foo(), $args);
}
// Using Global Reflection + Glbal foo
function m5($args) {
global $globalRefection, $globalFoo;
$globalRefection->invokeArgs($globalFoo, $args);
}
$result = array('m1' => 0,'m2' => 0,'m3' => 0,'m4' => 0,'m5' => 0);
$args = array("arg1","arg2");
for($i = 0; $i < 10000; ++ $i) {
foreach ( array_keys($result) as $key ) {
$alpha = microtime(true);
$key($args);
$result[$key] += microtime(true) - $alpha;
}
}
echo '<pre>';
echo "Single Run\n";
print_r($result);
echo '</pre>';
Output
Single Run
Array
(
[m1] => 0.018314599990845 <----- call_user_func_array
[m2] => 0.024132013320923 <----- ReflectionMethod:invoke
[m3] => 0.021934270858765 <----- ReflectionMethod:invokeArgs
[m4] => 0.012894868850708 <----- Global Relection
[m5] => 0.01132345199585 <----- Global Reflection + Global Foo
)
See Live Action

export variable to previous scope in PHP

Now, before you jump at how you shouldn't mix scopes: I realize this. However, this is a case where either scope mixing must occur or major code duplication must occur—nothing around it. And I'd prefer scope mixing.
That said, I'd like this code:
function a() {
$a = "a";
$b = "b";
$c = "c";
}
function b() {
a();
echo $a . $b . $c;
}
b(); // Output: abc
echo $a; // Should raise a notice that $a is undefined
to be able to work as commented. I know it's not possible in most languages—I was able to do it in Ruby, though; and wonder if you can do it with PHP.
The names of variables aren't known beforehand in the real situation.
Again, it's code duplication or this—absolutely no way around it.
Also, it'd be okay if a had to be something like a('b') or something.
In reality, the code is this:
static function renderError($what, $vararray) {
foreach($vararray as $key => $val) { /* this foreach is the code we want to decouple */
$key = 'e_'.$key;
$$key = htmlspecialchars($val);
}
ob_clean();
exit(eval('?>'.file_get_contents(ROOT."/templates/$what.php")));
}
With a call like E_Render::renderError('NotFound', array( 'requested_url' => '/notfound', 'misspelling' => '/reallynotfound' ));
Then, in templates/NotFound.php, you'd have something like:
<html>
<body>
<?php echo $e_requested_url; ?> could not be found. Did you mean <?php echo $e_misspelling: ?>?
</body>
</html>
We'd really rather not have our template authors do anything more than that...although $e['requested_url'] could be done if nothing better was available.
That's why we have OO:
class Foo {
function a() {
$this->a = "a";
$this->b = "b";
$this->c = "c";
}
function b() {
$this->a();
echo $this->a . $this->b . $this->c;
}
}
$f = new Foo;
$f->b(); // Output: abc
echo $a; // Should raise a notice that $a is undefined
Alternatively:
function a() {
$a = "a";
$b = "b";
$c = "c";
return compact('a', 'b', 'c');
}
function b() {
extract(a());
echo $a . $b . $c;
}
See: compact(), extract()
Otherwise I don't see a way of doing this without drastically changing the language.
PS: If you feel this feature is so important, why don't you just use Ruby?
There's no way to do what you're asking given the restrictions you are imposing. There's never going to be a good reason to do exactly what you are trying to do. There's plenty of better solutions.
Anyway, the closest you'll get is passing by reference:
<?php
function a(&$a, &$b, &$c)
{
$a = 1;
$b = 2;
$c = 3;
}
function b()
{
a($a, $b, $c);
}
?>
I just ran this code
-- var1.php
<?php
function a($vars) {
foreach ($vars as $var => $val) {
$$var = $val;
}
echo eval('?>' . file_get_contents('var2.php') . '<?php ');
};
a(array('a' => 'foo', 'b' => 'bar', 'c' => 'baz'));
-- var2.php
<html>
<body>
<div><?= '$a = "' . $a . '"' ?></div>
<div><?= '$b = "' . $b . '"' ?></div>
<div><?= '$c = "' . $c . '"' ?></div>
</body>
</html>
And it outputs :
$a = "foo"
$b = "bar"
$c = "baz"
The reason being that since eval() keeps the current scope, any variable declared locally inside the function will also be available locally inside the eval'ed string. Same thing with $this.
** UPDATE **
Since eval() is evil and should be avoided (as kindly suggested), here's a rewrite using simple templating. This way, your designer only has to know the variable name available (in the specs) :
-- var1.php
<?php
function showError($error, $vars) {
$template = file_get_contents("{$error}.php");
$keys = array();
$values = array();
foreach ($vars as $var => $val) {
$keys[] = '#{e_'.$var.'}';
$values[] = $val;
}
echo str_replace($keys, $values, $template);
};
showError('template1', array('value' => 300, 'message' => 'Something foo'));
-- template1.php
<html>
<body>
<div>Error <span style="font-weight: bold; color: red;">#{e_value}</span></div>
<div>The message was : <em>#{e_message}</em></div>
</body>
</html>
why can't you return $a from a()?
function a() {
$a = "a";
return $a;
}
function b() {
$a = a();
echo $a;
}
b(); // Output: a
echo $a; // Should raise a notice that $a is undefined
this does not break scope.
I do not understand why you cannot return them as an array. Besides the suggestion #NullUserException gave you, I would suggest the following approach (if you do not take the OOP route).
function a() {
$a = "a";
$b = "b";
$c = "c";
return array($a, $b, $c);
}
function b() {
list($a, $b, $c) = a();
echo $a . $b . $c;
}

PHP: Is it possible to return multiple values from a function? [duplicate]

Is it possible to have a function with two returns like this:
function test($testvar)
{
// Do something
return $var1;
return $var2;
}
If so, how would I be able to get each return separately?
Technically, you can't return more than one value. However, there are multiple ways to work around that limitation. The way that acts most like returning multiple values, is with the list keyword:
function getXYZ()
{
return array(4,5,6);
}
list($x,$y,$z) = getXYZ();
// Afterwards: $x == 4 && $y == 5 && $z == 6
// (This will hold for all samples unless otherwise noted)
Technically, you're returning an array and using list to store the elements of that array in different values instead of storing the actual array. Using this technique will make it feel most like returning multiple values.
The list solution is a rather php-specific one. There are a few languages with similar structures, but more languages that don't. There's another way that's commonly used to "return" multiple values and it's available in just about every language (in one way or another). However, this method will look quite different so may need some getting used to.
// note that I named the arguments $a, $b and $c to show that
// they don't need to be named $x, $y and $z
function getXYZ(&$a, &$b, &$c)
{
$a = 4;
$b = 5;
$c = 6;
}
getXYZ($x, $y, $z);
This technique is also used in some functions defined by php itself (e.g. $count in str_replace, $matches in preg_match). This might feel quite different from returning multiple values, but it is worth at least knowing about.
A third method is to use an object to hold the different values you need. This is more typing, so it's not used quite as often as the two methods above. It may make sense to use this, though, when using the same set of variables in a number of places (or of course, working in a language that doesn't support the above methods or allows you to do this without extra typing).
class MyXYZ
{
public $x;
public $y;
public $z;
}
function getXYZ()
{
$out = new MyXYZ();
$out->x = 4;
$out->y = 5;
$out->z = 6;
return $out;
}
$xyz = getXYZ();
$x = $xyz->x;
$y = $xyz->y;
$z = $xyz->z;
The above methods sum up the main ways of returning multiple values from a function. However, there are variations on these methods. The most interesting variations to look at, are those in which you are actually returning an array, simply because there's so much you can do with arrays in PHP.
First, we can simply return an array and not treat it as anything but an array:
function getXYZ()
{
return array(1,2,3);
}
$array = getXYZ();
$x = $array[0];
$y = $array[1];
$z = $array[2];
The most interesting part about the code above is that the code inside the function is the same as in the very first example I provided; only the code calling the function changed. This means that it's up to the one calling the function how to treat the result the function returns.
Alternatively, one could use an associative array:
function getXYZ()
{
return array('x' => 4,
'y' => 5,
'z' => 6);
}
$array = getXYZ();
$x = $array['x'];
$y = $array['y'];
$z = $array['z'];
Php does have the compact function that allows you to do same as above but while writing less code. (Well, the sample won't have less code, but a real world application probably would.) However, I think the amount of typing saving is minimal and it makes the code harder to read, so I wouldn't do it myself. Nevertheless, here's a sample:
function getXYZ()
{
$x = 4;
$y = 5;
$z = 6;
return compact('x', 'y', 'z');
}
$array = getXYZ();
$x = $array['x'];
$y = $array['y'];
$z = $array['z'];
It should be noted that while compact does have a counterpart in extract that could be used in the calling code here, but since it's a bad idea to use it (especially for something as simple as this) I won't even give a sample for it. The problem is that it will do "magic" and create variables for you, while you can't see which variables are created without going to other parts of the code.
Finally, I would like to mention that list doesn't really play well with associative array. The following will do what you expect:
function getXYZ()
{
return array('x' => 4,
'y' => 5,
'z' => 6);
}
$array = getXYZ();
list($x, $y, $z) = getXYZ();
However, the following will do something different:
function getXYZ()
{
return array('x' => 4,
'z' => 6,
'y' => 5);
}
$array = getXYZ();
list($x, $y, $z) = getXYZ();
// Pay attention: $y == 6 && $z == 5
If you used list with an associative array, and someone else has to change the code in the called function in the future (which may happen just about any situation) it may suddenly break, so I would recommend against combining list with associative arrays.
There is no way of returning 2 variables. Although, you can propagate an array and return it; create a conditional to return a dynamic variable, etc.
For instance, this function would return $var2
function wtf($blahblah = true) {
$var1 = "ONe";
$var2 = "tWo";
if($blahblah === true) {
return $var2;
}
return $var1;
}
In application:
echo wtf();
//would echo: tWo
echo wtf("not true, this is false");
//would echo: ONe
If you wanted them both, you could modify the function a bit
function wtf($blahblah = true) {
$var1 = "ONe";
$var2 = "tWo";
if($blahblah === true) {
return $var2;
}
if($blahblah == "both") {
return array($var1, $var2);
}
return $var1;
}
echo wtf("both")[0]
//would echo: ONe
echo wtf("both")[1]
//would echo: tWo
list($first, $second) = wtf("both")
// value of $first would be $var1, value of $second would be $var2
In your example, the second return will never happen - the first return is the last thing PHP will run. If you need to return multiple values, return an array:
function test($testvar) {
return array($var1, $var2);
}
$result = test($testvar);
echo $result[0]; // $var1
echo $result[1]; // $var2
Since PHP 7.1 we have proper destructuring for lists.
Thereby you can do things like this:
$test = [1, 2, 3, 4];
[$a, $b, $c, $d] = $test;
echo($a);
> 1
echo($d);
> 4
In a function this would look like this:
function multiple_return() {
return ['this', 'is', 'a', 'test'];
}
[$first, $second, $third, $fourth] = multiple_return();
echo($first);
> this
echo($fourth);
> test
Destructuring is a very powerful tool. It's capable of destructuring key=>value pairs as well:
["a" => $a, "b" => $b, "c" => $c] = ["a" => 1, "b" => 2, "c" => 3];
Take a look at the new feature page for PHP 7.1:
New features
In PHP 5.5 there is also a new concept: generators, where you can yield multiple values from a function:
function hasMultipleValues() {
yield "value1";
yield "value2";
}
$values = hasMultipleValues();
foreach ($values as $val) {
// $val will first be "value1" then "value2"
}
Or you can pass by reference:
function byRef($x, &$a, &$b)
{
$a = 10 * $x;
$b = 100 * $x;
}
$a = 0;
$b = 0;
byRef(10, $a, $b);
echo $a . "\n";
echo $b;
This would output
100
1000
For PHP 7.1.0 onwards, you can use the new syntax (instead of the list function):
/**
* #return array [foo, bar]
*/
function getFooAndBar(): array {
return ['foo', 'bar'];
}
[$foo, $bar] = getFooAndBar();
print 'Hello '. $foo . ' and ' . $bar;
It's OK for me if you want to return 2-3 variables, otherwise you should use an object with the desired properties.
I know that I am pretty late, but there is a nice and simple solution for this problem.
It's possible to return multiple values at once using destructuring.
function test()
{
return [ 'model' => 'someValue' , 'data' => 'someothervalue'];
}
Now you can use this
$result = test();
extract($result);
extract creates a variable for each member in the array, named after that member. You can therefore now access $model and $data
You can return multiple arrays and scalars from a function
function x()
{
$a=array("a","b","c");
$b=array("e","f");
return array('x',$a,$b);
}
list ($m,$n,$o)=x();
echo $m."\n";
print_r($n);
print_r($o);
Its not possible have two return statement. However it doesn't throw error but when function is called you will receive only first return statement value.
We can use return of array to get multiple values in return. For Example:
function test($testvar)
{
// do something
//just assigning a string for example, we can assign any operation result
$var1 = "result1";
$var2 = "result2";
return array('value1' => $var1, 'value2' => $var2);
}
Best Practice is to put your returned variables into array and then use list() to assign array values to variables.
<?php
function add_subt($val1, $val2) {
$add = $val1 + $val2;
$subt = $val1 - $val2;
return array($add, $subt);
}
list($add_result, $subt_result) = add_subt(20, 7);
echo "Add: " . $add_result . '<br />';
echo "Subtract: " . $subt_result . '<br />';
?>
Functions, by definition, only return one value.
However, as you assumed, that value can be an array.
So you can certainly do something like:
<?PHP
function myfunc($a,$b){
return array('foo'=>$a,'bar'=>$b);
}
print_r(myfunc('baz','bork'));
That said, it's worth taking a moment and thinking about whatever you're trying to solve. While returning a complex result value (like an array, or an object) is perfectly valid, if you're thinking is that "I want to return two values", you might be designing poorly. Without more detail in your question, it's hard to say, but it never hurts to stop and think twice.
The answer that's given the green tick above is actually incorrect. You can return multiple values in PHP, if you return an array. See the following code for an example:
<?php
function small_numbers()
{
return array (0, 1, 2);
}
list ($zero, $one, $two) = small_numbers();
This code is actually copied from the following page on PHP's website: http://php.net/manual/en/functions.returning-values.php
I've also used the same sort of code many times myself, so can confirm that it's good and that it works.
Yes, you can use an object :-)
But the simplest way is to return an array:
return array('value1', 'value2', 'value3', '...');
I have implement like this for multiple return value PHP function. be nice with your code. thank you.
<?php
function multi_retun($aa)
{
return array(1,3,$aa);
}
list($one,$two,$three)=multi_retun(55);
echo $one;
echo $two;
echo $three;
?>
PHP 7.1 Update
Return an array.
function test($testvar)
{
// Do something
return [$var1, $var2];
}
then use that like below:
[$value1, $value2] = test($testvar);
Functions in PHP can return only one variable. you could use variables with global scope, you can return array, or you can pass variable by reference to the function and than change value,.. but all of that will decrease readability of your code.
I would suggest that you look into the classes.
Thought I would expand on a few of the responses from above....
class nameCheck{
public $name;
public function __construct(){
$this->name = $name;
}
function firstName(){
// If a name has been entered..
if(!empty($this->name)){
$name = $this->name;
$errflag = false;
// Return a array with both the name and errflag
return array($name, $errflag);
// If its empty..
}else if(empty($this->name)){
$errmsg = 'Please enter a name.';
$errflag = true;
// Return both the Error message and Flag
return array($errmsg, $errflag);
}
}
}
if($_POST['submit']){
$a = new nameCheck;
$a->name = $_POST['name'];
// Assign a list of variables from the firstName function
list($name, $err) = $a->firstName();
// Display the values..
echo 'Name: ' . $name;
echo 'Errflag: ' . $err;
}
?>
<form method="post" action="<?php $_SERVER['PHP_SELF']; ?>" >
<input name="name" />
<input type="submit" name="submit" value="submit" />
</form>
This will give you a input field and a submit button once submitted, if the name input field is empty it will return the error flag and a message. If the name field has a value it will return the value/name and a error flag of 0 for false = no errors.
Hope this helps!
Some might prefer returning multiple values as object:
function test() {
$object = new stdClass();
$object->x = 'value 1';
$object->y = 'value 2';
return $object;
}
And call it like this:
echo test()->x;
Or:
$test = test();
echo $test->y;
Yes and no. You can't return more than one variable / object, but as you suggest, you can put them into an array and return that.
There is no limit to the nesting of arrays, so you can just package them up that way to return.
You can always only return one variable which might be an array. But You can change global variables from inside the function. That is most of the time not very good style, but it works. In classes you usually change class varbiables from within functions without returning them.
The answer is no. When the parser reaches the first return statement, it will direct control back to the calling function - your second return statement will never be executed.
Add all variables in an array and then finally return the array.
function test($testvar)
{
// do something
return array("var1" => $var1, "var2" => #var2);
}
And then
$myTest = test($myTestVar);
//$myTest["var1"] and $myTest["var2"] will be usable
I think eliego has explained the answer clearly. But if you want to return both values, put them into a array and return it.
function test($testvar)
{
// do something
return array('var1'=>$var1,'var2'=>$var2);
//defining a key would be better some times
}
//to access return values
$returned_values = test($testvar);
echo $returned_values['var1'];
echo $returned_values['var2'];
<?php
function foo(){
$you = 5;
$me = 10;
return $you;
return $me;
}
echo foo();
//output is just 5 alone so we cant get second one it only retuns first one so better go with array
function goo(){
$you = 5;
$me = 10;
return $you_and_me = array($you,$me);
}
var_dump(goo()); // var_dump result is array(2) { [0]=> int(5) [1]=> int(10) } i think thats fine enough
?>
Languages which allow multiple returns usually just convert the multiple values into a data structure.
For example, in Python you can return multiple values. However, they're actually just being returned as one tuple.
So you can return multiple values in PHP by just creating a simple array and returning that.
You can get the values of two or more variables by setting them by reference:
function t(&$a, &$b) {
$a = 1;
$b = 2;
}
t($a, $b);
echo $a . ' ' . $b;
Output:
1 2
Does PHP still use "out parameters"? If so, you can use the syntax to modify one or more of the parameters going in to your function then. You would then be free to use the modified variable after your function returns.
$var1 = 0;
$var2 = 0;
function test($testvar, &$var1 , &$var2)
{
$var1 = 1;
$var2 = 2;
return;
}
test("", $var1, $var2);
// var1 = 1, var2 = 2
It's not a good way, but I think we can set two variables in a function at the same time.
This is the easiest way to do it:
public function selectAllUsersByRole($userRole, $selector) {
$this->userRole = $userLevel;
$this->selector = $selector;
$sql = "SELECT * FROM users WHERE role <= ? AND del_stat = 0";
$stm = $this->connect()->prepare($sql); // Connect function in Dbh connect to database file
$stm->execute([$this->userRole]); // This is PHP 7. Use array($this->userRole) for PHP 5
$usersIdArray = array();
$usersFNameArray = array();
$usersLNameArray = array();
if($stm->rowCount()) {
while($row = $stm->fetch()) {
array_push($usersIdArray, $row['id']);
array_push($usersFNameArray, $row['f_name']);
array_push($usersLNameArray, $row['l_name']);
// You can return only $row['id'] or f_name or ...
// I used the array because it's most used.
}
}
if($this->selector == 1) {
return $usersIdArray;
}elseif($this->selector == 2) {
return $usersFNameArray;
}elseif($this->selector == 3) {
return $usersLNameArray;
}
}
How can we call this function?
$idData = $selectAllUsers->selectAllUsersByLevel($userRole, 0);
print_r($idData);
$idFName = $selectAllUsers->selectAllUsersByLevel($userRole, 1);
print_r($idFname);
That's it. Very easy.

Categories