pass function by reference - php

Well, I know what references are and when it's use is obvious.
One thing I really can't get is that when it's better to pass function by reference.
<?php
//right here, I wonder why and when
function &test(){
}
To avoid confusion, there're some examples as how I understand the references,
<?php
$numbers = array(2,3,4);
foreach ($numbers as &$number){
$number = $number * 2;
}
// now numbers is $numbers = array(4,6,8);
$var = 'test';
$foo = &var; //now all changes to $foo will be affected to $var, because we've assigned simple pointer
//Similar to array_push()
function add_key(&$array, $key){
return $array[$key];
}
//so we don't need to assign returned value from this function
//we just call this one
$array = array('a', 'b');
add_key($array,'c');
//now $array is ('a', 'b', 'c');
All benefits of using the references are obvious to me, except the use of "passing function by reference",
Question: When to pass function by reference (I've searched answer here, but still can't grasp this one)
Thanks

This is a function that returns by reference -- the term "passing a function by reference" is a bit misleading:
function &test(){
return /* something */;
}
The use cases are pretty much the same as for normal references, which is to say not common. For a (contrived) example, consider a function that finds an element in an array:
$arr = array(
array('name' => 'John', 'age' => 20),
array('name' => 'Mary', 'age' => 30),
);
function &findPerson(&$list, $name) {
foreach ($list as &$person) {
if ($person['name'] == $name) {
return $person;
}
}
return null;
}
$john = &findPerson($arr, 'John');
$john['age'] = 21;
print_r($arr); // changing $john produces a visible change here
See it in action.
In the above example, you have encapsulated the code that searches for an item inside a data structure (which in practice could be a lot more complicated than this array) in a function that can be reused. If you intend to use the return value to modify the original structure itself there's no other option than returning a reference from the function (in this specific case you could also have returned an index into the array, but think about structures that do not have indexes, e.g. graphs).

Do you means Returning References ?
A simple example is:
function &test(&$a){
return $a;
}
$a = 10;
$b = &test($a);
$b++;
// here $a became 11
var_dump($a);

Related

Dumping many variables in PHP

I assure this is a very common situation when you have to test variables (and they are many!), just like this example (I only named vars like this for less-effort-writing sake):
$variable0='red';
$variable1='blue';
$variable2='green';
$variable3='pink';
$variable4='purple';
$variable5='hellow';
$variable6='foo';
$variable7='bar';
$variable8='hi';
$variable9='bye';
echo
'$variable0='.$variable0.'<br>
$variable1='.$variable1.'<br>
$variable2='.$variable2.'<br>
$variable3='.$variable3.'<br>
$variable4='.$variable4.'<br>
$variable5='.$variable5.'<br>
$variable6='.$variable6.'<br>
$variable7='.$variable7.'<br>
$variable8='.$variable8.'<br>
$variable9='.$variable9;
My question is: is there a better way to make this echoing / dumping / printing easier?
Of course, there are other ways of doing the very same presidiary work:
$x=
'$variable0='."$variable0\n".
'$variable1='."$variable1\n".
'$variable2='."$variable2\n".
'$variable3='."$variable3\n".
'$variable4='."$variable4\n".
'$variable5='."$variable5\n".
'$variable6='."$variable6\n".
'$variable7='."$variable7\n".
'$variable8='."$variable8\n".
'$variable9='."$variable9"
echo nl2br($x);
Or:
$x=<<<HEREDOC
\$variable1=$variable1
\$variable2=$variable2
\$variable3=$variable3
\$variable4=$variable4
\$variable5=$variable5
\$variable6=$variable6
\$variable7=$variable7
\$variable8=$variable8
\$variable9=$variable9;
HEREDOC;
echo nl2br($x);
But maybe PHP has a function to make this easier?
By the way, all 3 solutions above echoes the very same:
$variable1=blue<br>
$variable2=green<br>
$variable3=pink<br>
$variable4=purple<br>
$variable5=hellow<br>
$variable6=foo<br>
$variable7=bar<br>
$variable8=hi<br>
$variable9=bye;
Introducing compact:
var_dump(compact('foo', 'bar', 'baz'));
Note though that I explicitly used three very different variables: $foo, $bar and $baz.
If you actually do literally have $foo1, $foo2 etc, you're really really looking to use an array instead. Dumping that would be trivial too:
$foo = array();
$foo[0] = 'bar';
$foo[1] = 'baz';
var_dump($foo);
In general, if you have too many variables floating around, your scope is probably too big and you should refactor everything into a number of smaller functions, or your algorithm is more complex than it needs to be, or you should be using arrays or other data structures instead.
get_defined_vars() would be able to do so. Might be overkill (all accessable vars will be shown):
print_r( get_defined_vars() );
Return Values: A multidimensional array with all the defined variables*.
*In a function it will only show the local $vars, and those defined as global.
Note: This does exactly what you're looking for, but the array methods mentioned in other answers would be a better fit logical-wise, see below:
A better way for you to set the values is with an array, this way you 'group' multiple values together:
$color[] = 'red'; // will automatically start with key=0
$color[] = 'blue'; // key=1
$color[] = 'green';// key=2 etc
print_r( $color );
echo $color[1]; // Blue, same as your echo $variable1;
You can declare your variables as keys from an array instead
$myarray=Array();
$myarray['variable0']='red';
$myarray['variable1']='blue';
$myarray['variable2']='green';
$myarray['variable3']='pink';
$myarray['variable4']='purple';
$myarray['variable5']='hellow';
$myarray['variable6']='foo';
$myarray['variable7']='bar';
$myarray['variable8']='hi';
$myarray['variable9']='bye';
and print them all with
echo '<pre>';
print_r($myarray);
echo '</pre>';
then, in case you still need to use them as separate variables, doing
extract($myarray)
will create $variable0 to $variable9 in the global context.
If you know the upper and lower bounds and all the variables have a similar name you could do the following:
for ($i = 0; $i < $end; ++$i) { echo ${'value_name'. $i}; }
Try refactor your code and use arrays
Then you can do print_r or var_dump
This should give you the output your looking for:
function get_var_name($var) {
foreach($GLOBALS as $var_name => $value) {
if ($value === $var) {
return $var_name;
}
}
return "Variable name not found";
}
function miracle_var_dump($valuesToDump) {
//For each variable in the $valuesToDump array, print the name and value
for($i = 0; $i < count($valuesToDump); $i++) {
echo(get_var_name($valuesToDump[i]) . "=" . $valuesToDump[i] . "<br/>");
}
}
//Making a call to dump the variables
miracle_var_dump(array($variable0,$variable1,$variable2,$variable3,$variable4,$variable5,$variable6,$variable7,$variable8,$variable9))
Function get_var_name gets the variable name given the variable (taken from one of Jeremey Rutins awsners).
//let your variables like this
$variable0='red';
$variable1='blue';
$variable2='green';
//an array to keep all the variable names
$var_names=array();
$var_names[]='$variable0';
$var_names[]='$variable1';
$var_names[]='$variable2';
//etc...
print_var_name($var_names);
function print_var_name($var_names) {
//loop through the array and dump them if they are in $GLOBALS
foreach($GLOBALS as $var_name => $value) {
if (in_array('$'.$var_name,$var_names)) {
echo $var_name;
var_dump($value);
}
}

PHP References: An understanding

I have seen in my journey to creaitng and building some of my php applications, the & symbol within front of vars, = and class names.
I understand that these are PHP References, but the docs i have seen and looked at seem to just not explain it in a way that i understand or confusing. How can you explain the following examples that i have seen to make them more understandable.
public static function &function_name(){...}
$varname =& functioncall();
function ($var, &$var2, $var3){...}
Much appreciated
Let's say you have two functions
$a = 5;
function withReference(&$a) {
$a++;
}
function withoutReference($a) {
$a++;
}
withoutReference($a);
// $a is still 5, since your function had a local copy of $a
var_dump($a);
withReference($a);
// $a is now 6, you changed $a outside of function scope
var_dump($a);
So, passing argument by reference allows function to modify it outside of the function scope.
Now second example.
You have a function which returns a reference
class References {
public $a = 5;
public function &getA() {
return $this->a;
}
}
$references = new References;
// let's do regular assignment
$a = $references->getA();
$a++;
// you get 5, $a++ had no effect on $a from the class
var_dump($references->getA());
// now let's do reference assignment
$a = &$references->getA();
$a++;
// $a is the same as $reference->a, so now you will get 6
var_dump($references->getA());
// a little bit different
$references->a++;
// since $a is the same as $reference->a, you will get 7
var_dump($a);
Reference functions
$name = 'alfa';
$address = 'street';
//declaring the function with the $ tells PHP that the function will
//return the reference to the value, and not the value itself
function &function_name($what){
//we need to access some previous declared variables
GLOBAL $name,$address;//or at function declaration (use) keyword
if ($what == 'name')
return $name;
else
return $address;
}
//now we "link" the $search variable and the $name one with the same value
$search =& function_name('name');
//we can use the result as value, not as reference too
$other_search = function_name('name');
//any change on this reference will affect the "$name" too
$search = 'new_name';
var_dump($search,$name,$other_search);
//will output string 'new_name' (length=8)string 'new_name' (length=8)string 'alfa' (length=4)
Usually you use the method with Objects that implemented the same interface, and you want to choose the object you want to work with next.
Passing by reference:
function ($var, &$var2, $var3){...}
I'm sure you saw the examples, so I'll just explain how and when to use it.
The basic scenario is when do you have a big logic that you want to apply to a current object/data, and you do not wish to make more copies of it (in memory).
Hope this helps.

PHP function returning two arrays

I have a function and I need it to return two arrays.
I know a function can only return one variable .. is there a way to return my two arrays?
If I concatenate them, how can I separate them cleanly when out of the function?
No need to concatenate: just return array of two arrays, like this:
function foo() {
return array($firstArray, $secondArray);
}
... then you will be able to assign these arrays to the local variables with list, like this:
list($firstArray, $secondArray) = foo();
And if you work with PHP 5.4, you can use array shortcut syntax here as well:
function foo54() {
return [$firstArray, $secondArray];
}
I think raina77ow's answer adequately answers your question. Another option to consider is to use write parameters.
function foobar(array &$arr1 = null)
{
if (null !== $arr1) {
$arr1 = array(1, 2, 3);
}
return array(4, 5, 6);
}
Then, to call:
$arr1 = array();
$arr2 = foobar($arr1);
This won't be useful if you always need to return two arrays, but it can be used to always return one array and return the other only in certain cases.

Efficiency of using foreach loops to clear a PHP array's values

Which is more efficient for clearing all values in an array? The first one would require me to use that function each time in the loop of the second example.
foreach ($array as $i => $value) {
unset($array[$i]);
}
Or this
foreach($blah_blah as $blah) {
$foo = array();
//do something
$foo = null;
}
I don't want to use unset() because that deletes the variable.
Like Zack said in the comments below you are able to simply re-instantiate it using
$foo = array(); // $foo is still here
If you want something more powerful use unset since it also will clear $foo from the symbol table, if you need the array later on just instantiate it again.
unset($foo); // $foo is gone
$foo = array(); // $foo is here again
If we are talking about very large tables I'd probably recommend
$foo = null;
unset($foo);
since that also would clear the memory a bit better. That behavior (GC) is however not very constant and may change over PHP versions. Bear in mind that re-instantiating a structure is not the same as emptying it.
If you just want to reset a variable to an empty array, you can simply reinitialize it:
$foo = array();
Note that this will maintain any references to it:
$foo = array(1,2,3);
$bar = &$foo;
// ...
$foo = array(); // clear array
var_dump($bar); // array(0) { } -- bar was cleared too!
If you want to break any references to it, unset it first:
$foo = array(1,2,3);
$bar = &$foo;
// ...
unset($foo); // break references
$foo = array(); // re-initialize to empty array
var_dump($bar); // array(3) { 1, 2, 3 } -- $bar is unchanged
Unsetting the variable is a nice way, unless you need the reference of the original array!
To make clear what I mean:
If you have a function wich uses the reference of the array, for example a sorting function like
function special_sort_my_array(&$array)
{
$temporary_list = create_assoziative_special_list_out_of_array($array);
sort_my_list($temporary_list);
unset($array);
foreach($temporary_list as $k => $v)
{
$array[$k] = $v;
}
}
it is not working! Be careful here, unset deletes the reference, so the variable $array is created again and filled correctly, but the values are not accessable from outside the function.
So if you have references, you need to use $array = array() instead of unset, even if it is less clean and understandable.
I'd say the first, if the array is associative. If not, use a for loop:
for ($i = 0; $i < count($array); $i++) { unset($array[$i]); }
Although if possible, using
$array = array();
To reset the array to an empty array is preferable.
Isn't unset() good enough?
unset($array);
How about $array_name = array(); ?
Use array_splice to empty an array and retain the reference:
array_splice($myArray, 0);
i have used unset() to clear the array but i have come to realize that unset() will render the array null hence the need to re-declare the array like for example
<?php
$arr = array();
array_push($arr , "foo");
unset($arr); // this will set the array to null hence you need the line below or redeclaring it.
$arr = array();
// do what ever you want here
?>
Maybe simple, economic way (less signs to use)...
$array = [];
We can read in php manual :
As of PHP 5.4 you can also use the short array syntax, which replaces array() with [].
I see this questions is realla old, but for that problem I wrote a recursive function to unset all values in an array. Recursive because its possible that values from the given array are also an array. So that works for me:
function empty_array(& $complete_array) {
foreach($complete_array as $ckey => $cvalue)
{
if (!is_array($cvalue)) {
$complete_array[$ckey] = "";
} else {
empty_array( $complete_array[$ckey]);
}
}
return $complete_array;
}
So with that i get the array with all keys and sub-arrays, but empty values.
The unset function is useful when the garbage collector is doing its rounds while not having a lunch break;
however unset function simply destroys the variable reference to the data, the data still exists in memory and PHP sees the memory as in use despite no longer having a pointer to it.
Solution:
Assign null to your variables to clear the data, at least until the garbage collector gets a hold of it.
$var = null;
and then unset it in similar way!
unset($var);
The question is not really answered by the posts. Keeping the keys and clearing the values is the focus of the question.
foreach($resultMasterCleaned['header'] as $ekey => $eval) {
$resultMasterCleaned[$key][$eval] = "";
}
As in the case of a two dimensional array holding CSV values and to blank out a particular row. Looping through seems the only way.
[] is nearly 30% faster then as array()
similar as pushing new element to array
$array[] = $newElement then array_push($array, $newElement)
(keep in mind array_push is slower only for single or 2 new elements)
Reason is we skip overhead function to call those
PHP array vs [ ] in method and variable declaration

How do I use array_filter() for functional programming in PHP?

Say I have an array of tags
$all_tags = array('A', 'B', 'C');
And I want to create a set of URLs with $_GET variables.
I'd like the links to be:
'A' linking to "index.php?x[]=B&x[]=C"
'B' linking to "index.php?x[]=A&x[]=C"
etc. ($_GET is an array with all elements except for "current" element)
(I know there's an easier way to implement this: I'm actually simplifying a more complex situation)
I'd like to use array_filter() to solve this.
Here's my attempt:
function make_get ($tag) { return 'x[]=' . $tag; }
function tag_to_url ($tag_name) {
global $all_tags;
$filta = create_function('$x', 'global $all_tags; return ($x != $tag_name);');
return 'index.php?' . implode('&', array_map("make_get", array_filter($all_tags, "filta")));
}
print_r(array_map("", $all_tags));
But it doesn't work. I have a suspicion that maybe it has to do with how maps and filters in PHP actually mutate the data structure themselves, and return a boolean, instead of using a functional style, where they don't mutate and return a new list.
I am also interested in other ways to make this code more succinct.
Here's an alternative approach:
// The meat of the matter
function get_link($array, $tag) {
$parts = array_reduce($array, function($result, $item) use($tag)
{
if($item != $tag) $result[] = 'x[]='.$tag;
return $result;
});
return implode('&', $parts);
}
// Test driver
$all_tags = array('A', 'B', 'C');
echo get_link($all_tags, 'A');
echo "\n";
echo get_link($all_tags, 'B');
echo "\n";
echo get_link($all_tags, 'C');
echo "\n";
It's simply one call to array_reduce, and then an implode to pull the results together into a query string.
Something approaching real support for functional programming styles in PHP is very, very new--it was only in PHP 5.3 that functions became first class and anonymous functions were possible.
BTW, you should never use create_function(). What it really does is define a new function in the global namespace (which will never be garbage-collected!), and it uses eval() behind the scenes.
If you have PHP 5.3 or greater, you can do this:
$all_tags = array('A', 'B', 'C');
function is_not_equal($a, $b) {
return $a != $b;
}
function array_filter_tagname($alltags, $name) {
$isNotEqualName = function($item) use ($name){
return is_not_equal($item, $name);
};
// array_merge() is ONLY to rekey integer keys sequentially.
// array_filter() preserves keys.
return array_merge(array_filter($alltags, $isNotEqualName));
}
function make_url($arr) {
return 'input.php?'.http_build_query(array('x'=>$arr));
}
$res = array_filter_tagname($all_tags, 'B');
print_r($res);
print_r(make_url($res));
If you have a PHP < 5.3, you should use a class+object for your closures instead of create_function().
class NotEqualName {
protected $otheritem;
function __construct($otheritem) { // with PHP 4, use "function NotEqualName($otheritem) {"
$this->otheritem = $otheritem;
}
function compare($item) {
return $item != $this->otheritem;
}
}
function array_filter_tagname_objectcallback($alltags, $name) {
$isNotEqualName = new NotEqualName($name);
return array_merge(array_filter($alltags, array($isNotEqualName,'compare')));
}
In general, however, PHP is not very well suited to a functional style, and for your particular task using array_filter() is not very idiomatic PHP. array_diff() is a better approach.
Based on an answer I gave in the comments (shown here):
<?php
$all_tags = array('A', 'B', 'C');
function tag_to_url($tag_name)
{
global $all_tags;
$remaining_tags = array_diff($all_tags, array($tag_name));
return sprintf('index.php?%s',
http_build_query(array('x'=>array_values($remaining_tags))));
}
echo tag_to_url('B'); // index.php?x%5B0%5D=A&x%5B1%5D=C
// basically: index.php?x[0]=A&x[1]=C
Basically, use array_diff to remove the entry from the array (instead of filtering), then pass it off to the http_build_query to come up with a valid URL.
I'm just going to answer the "why it doesnt work" part.
$filta = create_function('$x', 'global $all_tags; return ($x != $tag_name);');
The tag_name variable is undefined in your lambda function's scope. Now, it is defined in the creating functions scope(tag_to_url). You can't exactly use the global keyword here either, because $tag_name isn't in the global scope, it is in the local tag_to_url scope. You could declare the variable in the global scope and then it could work, but considering you're fond of functional approaches, I doubt you like global variables :)
You could do trickery with string concatenation and var_export($tag_name) and pass that to create_function() if you wanted, but there's other better ways to achieve your goals.
Also, as an aside, I'm guessing you might benefit from turning up php's error reporting level while developing. php would have thrown undefined variable notices at you, which helps debugging and understanding.
// ideally set these in php.ini instead of in the script
error_reporting(E_ALL);
ini_set('display_errors', 1);

Categories