Is it possible to have an array and pass it into a function as separate arguments?
$name = array('test', 'dog', 'cat');
$name = implode(',' $name);
randomThing($name);
function randomThing($args) {
$args = func_get_args();
// Would be 'test', 'dog', 'cat'
print_r($args);
}
No. That's what call_user_func_array() is for.
As of PHP 5.6 you can use ... to pass an array as function arguments. See this example from the PHP documentation:
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2])."\n";
$a = [1, 2];
echo add(...$a);
Related
I am getting familiar with anonymous function and closures in php and I need to use a closure or anon function to pass to array_walk but with an additional parameter here is a simple code block:
$array = array(1, 2, 3, 4, 5, array(1, 2));
$callback = function(&$value, $key)
{
$value = $key*$value;
};
var_dump($array, array_walk_recursive($array, $callback), $array);
It is very simple as it is but say I want to change the function as follows:
$callback = function(&$value, $key, $multiplier)
{
$value = $key*$value*$multiplier;
};
How can I pass the multiplier to the anon function? Or if it should be a closure how can it be done.
Because as follows is giving me an error:
array_walk_recursive($array, $callback(5))
I know that array_walk has an extra param $user_data which can be passed but I need it with a closure or anon function.
PHP's closures can be used for this:
<?php
$array = array(1, 2, 3, 4, 5, array(1, 2));
$multiplier = 5;
$callback = function(&$value, $key) use ($multiplier) {
$value = $key*$value*$multiplier;
};
var_dump($array, array_walk_recursive($array, $callback), $array);
Obviously $multiplier can receive non-static values, like ta query argument or the result of a computation. Just make sure to validate and type cast to guarantee a numeric value.
You can use two options:
$mltpl = 10;
$callback = function(&$value, $key)
{
global $mltpl;
$value = $key*$value*$mltpl;
};
Or
$mltpl = 10;
$callback = function(&$value, $key) use ($mltpl)
{
$value = $key*$value*$mltpl;
};
This question is different than others, as it's focus is on sorting an array with a static class method rather than the typical procedural approach.
I am look for a very performant way to implement the function sortByKeyValue below. Other somewhat related answers are focused on getting the job done, this question is more about getting the job done and getting it done very quickly (as a static method).
Anyone want to take a crack at it? I'll probably throw some bounty on this question to squeeze out the performance junkies. :)
<?php
$data = array(
array('name' => 'B', 'cheesy' => 'bacon'),
array('name' => 'C', 'delicious' => 'tacos'),
array('name' => 'A', 'lovely' => 'viddles'),
);
class MyArray {
public static function sortByKeyValue($array, $key, $direction = 'ASC') {
// Do the thing
// Help me!
return $array;
}
}
$data = MyArray::sortByKeyValue($data, 'name');
// Should output the name key in order
// I am not including the garbage keys I threw in, but they should be there too)
// [{"name": "A"},{"name": "B"},{"name": "C"}]
?>
You can use usort with a closure (Available php 5.3+)
usort($array, function($a, $b){ return strcmp($a["name"], $b["name"]);});
Pre 5.3 you would have to create a sorter function and pass to usort
function arraySorter($a, $b){
return strcmp($a["name"], $b["name"]);
}
usort($array, "arraySorter");
Or you can place the arraySorter as a static method on your class
public static function _arraySorter($a, $b){
return strcmp($a["name"], $b["name"]);
}
// then call
usort($array, array("MyArray", "_arraySorter")); // for static
Note. This will perform an in place sort.
As Suggested by #Kirk in comments you can use a function to return an anonymous sorter function so the implementation isn't bound to the name property
function getSorter($property){
return function($a, $b) use ($property){
return strcmp($a[$property], $b[$property]);
};
}
Then you can call
usort($array, getSorter("name"));
I ran the following to compare the speed of multisort, a pre-PHP 5.3 method, with a more modern method that uses usort with a closure function:
$alpha = 'abcdefghijklmnopqrstuvwxyz';
$cnt = 1000;
$key = 'name';
$direction = 'ASC';
$array = array();
for ($i=0; $i<$cnt; $i++){
$array[$i]['name'] = substr(str_shuffle($alpha), 0, 8);
$array[$i]['job'] = substr(str_shuffle($alpha), 0, 8);
}
$pre = $array;//the test dummies
//PRE-PHP 5.3
$t[0] = -microtime();
$sub = array();
foreach ($pre as $item) {
$sub[] = $item[$key];
}
if ($direction == 'ASC') $ord = SORT_ASC;
else $ord = SORD_DESC;
array_multisort($sub, $ord, $pre);
$t[0] += microtime();
//USORT WITH CLOSURE
$t[1] = -microtime();
usort($array, function ($a, $b) use($key, $direction){
if ($direction == 'ASC'){
return strcmp($a[$key], $b[$key]);
}
return strcmp($b[$key], $a[$key]);
});
$t[1] += microtime();
var_dump($t);
As you can see, the old method was more than twice as fast:
Array
(
[0] => 0.005
[1] => 0.014001
)
So here's how I would do the class:
class MyArray {
public static function sortByKeyValue($array, $key, $direction = SORT_ASC) {
$sub = array();
foreach ($array as $item) {
$sub[] = $item[$key];
}
array_multisort($sub, $direction, $array);
return $array;
}
}
I prefer array_multisort():
<?php
$data = array(
array('name' => 'B', 'cheesy' => 'bacon'),
array('name' => 'C', 'delicious' => 'tacos'),
array('name' => 'A', 'lovely' => 'viddles'),
);
class MyArray {
public static function sortByKeyValue($array, $key, $direction = 'ASC') {
$tmp = array();
foreach($array as $k=>$r){
$tmp[] = $r[$key];
}
array_multisort($tmp,($direction == 'ASC' ? SORT_ASC : SORT_DESC),$array);
return $array;
}
}
$data = MyArray::sortByKeyValue($data, 'name');
echo '<pre>',print_r($data),'</pre>';
When writing controllers for Symfony 2, I often need to pass quite a few variables to the template like return array('param1' => $param1, 'anotherBigParam' => $anotherBigParam, 'yetAnotherParam' => $yetAnotherParam);
With many parameters this ends up really long and ugly, so I thought about creating a helper function for it:
public function indexAction()
{
$param1 = 'fee';
$anotherBigParam = 'foe';
$yetAnotherParam = 'fum';
return $this->vars('param1', 'anotherBigParam', 'yetAnotherParam');
}
private function vars() {
$arr = array();
foreach(func_get_args() as $arg) {
$arr[$arg] = $$arg;
}
return $arr;
}
Is there some kind of drawback or risk from doing this? Does PHP or Symfony 2 already provide a better or cleaner way to achieve the same result?
There is a native way of doing it: compact
$one = 'ONE';
$two = 'TWO';
$a = compact( 'one', 'two' );
print_r( $a );
/*
Array
(
[one] => ONE
[two] => TWO
)
*/
You're looking for compact.
public function indexAction()
{
$param1 = 'fee';
$anotherBigParam = 'foe';
$yetAnotherParam = 'fum';
return compact('param1', 'anotherBigParam', 'yetAnotherParam');
}
Can a PHP function return a lot of vars without array?
I want like that:
<?php
public function a()
{
$a = "a";
$b = "b";
$c = "c";
}
echo a()->a;
echo a()->b;
echo a()->c;
?>
How can I access to $a,$b,$c vars?
Instead of an array, you could use an associative array and cast it to an object, which allows you to access the elements using the -> object syntax:
function a()
{
return (object) array(
'a' => "a",
'b' => "b",
'c' => "c");
}
echo a()->a; // be aware that you are calling a() three times here
echo a()->b;
echo a()->c;
function a1() {
return array(
'a' => 'a',
'b' => 'b',
'c' => 'c'
);
}
$a1 = a1();
echo $a1['a'];
echo $a1['b'];
echo $a1['c'];
function a2() {
$result = new stdClass();
$result->a = "a";
$result->b = "b";
$result->c = "c";
return $result;
}
$a2 = a2();
echo $a2->a;
echo $a2->b;
echo $a2->c;
// or - but that'll result in three function calls! So I don't think you really want this.
echo a2()->a;
echo a2()->b;
echo a2()->c;
http://php.net/manual/en/function.list.php
Create a class that holds your 3 variables and return an instance of the class. Example:
<?php
class A {
public $a;
public $b;
public $c;
public function __construct($a, $b, $c) {
$this->a = $a;
$this->b = $b;
$this->c = $c;
}
}
function a() {
return new A("a", "b", "c");
}
echo a()->a;
echo a()->b;
echo a()->c;
?>
Of course the last 3 lines are not particularly efficient because a() gets called 3 times. A sensible refactoring would result in those 3 lines being changed to:
$a = a();
echo $a->a;
echo $a->b;
echo $a->c;
If you want to access those variables that way (without using an array), you should better use a class:
class Name{
var $a = "a";
var $b = "b";
}
$obj = new Name();
echo $obj->a;
You could build a class and return an object instead. Check out this SO answer for something that you might find useful.
Yes this is possible when the return variable has to be as an array or it should be long string with multiple values separated with any of the delimiters like ", | #" and so on.
if it is built as an array we can receive it using var_dump function available in PHP
see below code
var_dump($array);
PHP Manual > Returning values:
A function can not return multiple values, but similar results can be obtained by returning an array.
<?php
function small_numbers()
{
return array (0, 1, 2);
}
list ($zero, $one, $two) = small_numbers();
no need for classes here.
PHP functions such as 'array_map' take a callback, which can be a simple function or a class or object method:
$array2 = array_map('myFunc', $array);
or
$array2 = array_map(array($object, 'myMethod'), $array);
But is there a syntax to pass a method which is bound within the iteration to the current object (like 'invoke' in Prototype.js)? So that the following could be used:
$array2 = array_map('myMethod', $array);
with the effect of
foreach($array as $obj) $array2[] = $obj->myMethod();
Obviously I can use this form, or I can write a wrapper function to make the call, and even do that inline. But since 'myMethod' is already a method it seems to be going round the houses to have to do one of these.
Not currently. When php 5.3 comes out, you could use the following syntax:
$array2 = array_map(function($obj) { return $obj->myMethod(); }, $array);
function obj_array_map($method, $arr_of_objects) {
$out = array();
$args = array_slice(func_get_args(), 2);
foreach ($arr_of_objects as $key => $obj) {
$out[$key] = call_user_func_array(Array($obj, $method), $args);
}
return $out;
}
// this code
$a = Array($obj1, $obj2);
obj_array_map('method', $a, 1, 2, 3);
// results in the calls:
$obj1->method(1, 2, 3);
$obj2->method(1, 2, 3);
Basically, no. There is no special syntax to make this any easier.
I can think of a fancier way of doing this in PHP 5.3, seeing as there's always more than one way to do things in PHP, but I'd say it wouldn't necessarily be better than your foreach example:
$x = array_reduce(
$array_of_objects,
function($val, $obj) { $val = array_merge($val, $obj->myMethod()); return $val; },
array()
);
Just go with your foreach :)
<?php
// $obj->$method(); works, where $method is a string containing the name of the
// real method
function array_map_obj($method, $array) {
$out = array();
foreach ($array as $key => $obj)
$out[$key] = $obj->$method();
return $out;
}
// seems to work ...
class Foo {
private $y = 0;
public function __construct($x) {
$this->y = $x;
}
public function bar() {
return $this->y*2;
}
}
$objs = array();
for ($i=0; $i<20; $i++)
$objs[] = new Foo($i);
$res = array_map_obj('bar', $objs);
var_dump($res);
?>
voila!
This is a bit of a silly answer, but you could subclass ArrayObject and use that instead of a normal array:
<?php
class ArrayTest extends ArrayObject {
public function invokeMethod() {
$result = array();
$args = func_get_args();
$method = array_shift($args);
foreach ($this as $obj) {
$result[] = call_user_func_array(array($obj, $method), $args);
}
return $result;
}
}
//example class to use
class a {
private $a;
public function __construct($a) {
$this->a = $a;
}
public function multiply($n) {
return $this->a * $n;
}
}
//use ArrayTest instance instead of array
$array = new ArrayTest();
$array[] = new a(1);
$array[] = new a(2);
$array[] = new a(3);
print_r($array->invokeMethod('multiply', 2));
Outputs this:
Array
(
[0] => 2
[1] => 4
[2] => 6
)
I would use create_function() to ... well ... create a temporary function for array_map while waiting for PHP 5.3
$func = create_function('$o', '$o->myMethod();');
array_map($func, $objects);