This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to use an object method as a callback function
Usually I used array_map with procedural code, but in this case I'm working in OOP and the callback should be "this->id2areas", but It's not working. Is there anyway of put this callback with OOP?
ERROR MESSAGE: array_map() expects parameter 1 to be a valid callback, function 'this->id2area' not found or invalid function name
MY CODE
=================================================================================
$this->context->assign('user_areas', implode(', ', array_map('id2area', explode(',', $this->user['areas']))));
explode(',', $this->user['areas']))));
function id2area($id) {//callback
if ($id == 0) {
return 'National';
}
$query = "SELECT area FROM area WHERE id = $id";
return DB::fetch_instance()->slave->fetchColumn($query);
}
In PHP, you can use an array to associate an object and a method call as a callable
array_map(array($this, 'id2area'), $array);
http://php.net/manual/en/language.types.callable.php
PHP callbacks for objects is a bit different then global functions.
//Global function callback
array_map('id2area', $data);
// Object function
array_map(array($object, 'id2area'), $data)
// - or -
array_map(array($this, 'id2area'), $data)
// Static class function
array_map(array('Class_Name', 'id2area'), $data)
// - or -
array_map('Class_Name::id2area', $data)
http://us1.php.net/manual/en/language.types.callable.php
You could also do this as an anonymous function like:
array_map(
function($arg) {
return $this->id2area($arg);
},
explode(',', $this->user['areas'])
);
Related
I need to realize function "calc" that works like that:
$sum = function($a, $b) { return $a + $b; };
calc(5)(3)(2)($sum); // 10
calc(1)(2)($sum); // 3
calc(2)(3)('pow'); // 8
I can write something like this:
function calc(){;
print_r(func_get_args());
return __FUNCTION__;
}
calc(3)(5)(2)('sum');
and it print Array ( [0] => 3 ) Array ( [0] => 5 ) Array ( [0] => 2 ) Array ( [0] => sum ).
So, when I get 'sum' in my function, i should have an array with all previous arguments.
But i have no idea, how can i pass current argument in next function call to manipulate all of them on last iteration. Or is there some sort of recursive solution?
What you're talking about is called Currying. The following code will require PHP 7, since it involves invoking a function returned from another one, which wasn't possible until PHP's Abstract Syntax Tree was implemented in that version.
First things first, you'll need a new sum() function that can operate on an arbitrary number of variables:
$sum = function(...$args) { return array_sum($args); };
Secondly, the important part. A function that returns a new anonymous function, accumulating the arguments as it goes. When you finally pass it something callable (either your $sum function, or a built-in function name like pow), it'll execute it, unpacking the arguments that it's built up.
function calc($x)
{
return function($y = null) use ($x)
{
if (is_callable($y)) {
return $y(...$x);
} else {
$args = (array) $x;
$args[] = $y;
return calc($args);
}
};
}
echo calc(5)(3)(2)($sum); // 10
echo calc(1)(2)($sum); // 3
echo calc(2)(3)('pow'); // 8
See https://3v4l.org/r0emm
(Note that internal functions will be limited to operating on the number of arguments they are defined to take - calc(2)(3)(4)('pow') will raise an error.)
This isn't a particularly common pattern to use (which is probably why you've found it hard to track down), so please for everyone who reads it's sake, think carefully about where you use it.
Credit to the curryAdd answer in this question for the starting blocks.
Edit: I stand corrected, you don't require globals it seems! Definitely use the #iainn's answer over this one.
So to achieve this you're going to have to use globals if you're not doing it within a class to maintain current state. You can see a working example of the below code here (note that it only works for PHP version 7 and above)
<?php
$sum = function(...$args) {
return array_sum($args);
};
function calc(...$args) {
global $globalArguments;
if (is_callable($args[0])) {
$callback = $args[0];
$arguments = array_map(function ($arg) {
return $arg[0];
}, $globalArguments);
return $callback(...$arguments);
}
$globalArguments[] = $args;
return __FUNCTION__;
}
echo calc(3)(2)($sum); // 5
I don't know why you want to do this, but I don't suggest it in production, globals aren't something that should really be used if you can avoid it.
function calc(int $value, Callable $function = null)
{
return function ($v) use ($value, $function) {
$f = function ($call) use ($value, $function) {
return (is_callable($call) && is_callable($function)) ? $call($function($call), $value) : $value;
};
return is_callable($v) ? $f($v) : calc($v, $f);
};
}
This is my array
$sub = array("English"=>"12","Hindi"=>"12","History"=>"12","Geography"=>"12","Mathematics"=>"12","Physics"=>"12","Chemistry"=>"12","Biology"=>"12");
Want to pass this entire array as the parameter of a function & want to sum up the marks(array values) using the function
function sum_marks($sub){--Function body--
}
I don't know if this is the proper syntax for passing an array to a function, help!!
Is this you are looking for?
$mySum = array_sum($sub);
Yes, it is the appropriate syntax for passing an array as an argument to a function.
However, you might consider adding a type declaration for the $sub argument:
function sum_marks(array $sub)
{
return array_sum($sub);
}
Type declarations allow functions to require that parameters are of a certain type at call time. If the given value is of the incorrect type, then an error is generated: in PHP 5, this will be a recoverable fatal error, while PHP 7 will throw a TypeError exception.
However, you really probably just want to use array_sum() directly.
For reference, see:
http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration
http://php.net/manual/en/function.array-sum.php
Try this. It will create a function that has a reference to your array. When you change the array you can call the product of the function, and it will recalculate the sum.
$array = ['English' => '12', 'Swedish' => '12'];
function arraySumCb(&$subject) {
return function () use (&$subject) {
return array_sum($subject);
};
}
$sum = arraySumCb($array);
echo $sum(); // 24
$array['Swedish'] = '15';
echo $sum(); // 27
$array['Swedish'] = '10';
echo $sum(); // 22
Edit: This is how I would do it.
$array = ['English' => '12', 'Swedish' => '12'];
class SumMarks {
private $_subject;
public function __construct(array &$subject = []) {
$this->_subject = &$subject;
}
public function __toString() {
return "" . array_sum($this->_subject);
}
}
$sum = new SumMarks($array);
echo $sum; // 24
$array['Swedish'] = '10';
echo $sum; // 22
Edit: Proper use of PHP anonymous functions
I dont understand your question, please ask with specific question. .
But maybe this what are you want :
function sum_marks($sub){
$result = array_sum($sub);
retrun $result;
}
So my array contains objects like this:
$arr = array(
new Card('10', 'Spades'),
new Card('Jack', 'Diamonds'),
new Card('King', 'Spades')
);
Now I have a function:
function hasCard(Card $card) {
if (in_array($card, $arr)) return true;
return false;
}
Now above does not really work since I need to compare ($card->rank == $arr[$x]->rank) for each element in that $arr without looping. Is there a function on PHP that allows you to modify the compareTo method of array_search?
I'd suggest using array_filter here. (Note: make sure $arr is available inside the hasCard function)
function hasCard(Card $card) {
$inArray = array_filter($arr, function($x) use($card){
return $x->rank === $card->rank;
});
return count($inArray) > 0;
}
DEMO: https://eval.in/166460
The $arr variable is not going to be available within the function hasCard, unless you pass it as a parameter.
To answer your question, look at array_filter. This will get you a callable function in which you can pass the $arr and $card as parameters.
I have an associative array in the following form:
$params = array(
'paramName_4'=>'param_4',
'paramName_2'=>'param_2',
// ...,
'paramName_6'=>'param_6',
);
and I also have a function myFunction defined as:
public function myFunction($paramName_1, $paramName_2, $paramName_3, ....);
Does a a "parsing" function exist in PHP so that I can call function myFunction by matching the parameters (even if they are not sorted wrt the myFunction's parameter sequence)? In other words, can I do
my_magic(__NAMESPACE__.'\\myFunction', $params);
Does this "magic" function does exist? If not, how can I implement it?
You can implement it using reflection. Here's how:
// The input is the array of arguments and the function name
$arguments = array(....);
$functionName = __NAMESPACE__.'\\myFunction';
$reflector = new \ReflectionFunction($functioName);
$params = $reflector->getParameters();
$values = array();
foreach ($params as $param) {
$name = $param->getName();
$isArgumentGiven = array_key_exists($name, $arguments);
if (!$isArgumentGiven && !$param->isDefaultValueAvailable() {
die ("Parameter $name is mandatory but was not provided");
}
$values[$param->getPosition()] =
$isArgumentGiven ? $arguments[$name] : $param->getDefaultValue();
}
// You can now call the function:
call_user_func($functionName, $values);
Yes, you can use Reflection as per #Jon's example, but if the problem is just that the params aren't in the right order, why not just use ksort() or uksort() to put them in the right order.
Then you can use call_user_func_array(). Problem solved.
$params = array(....);
uksort($params, function($a,$b) {
//sort the params into the known order....
$sortOrder = array('param1','param2','param3','param4');
return (array_search($a, $sortOrder) > array_search($b, $sortOrder)) ? -1 : 1;
});
//now that $params is in the right order we can do this....
$retVal = call_user_func_array($func, $params);
I've hard-coded the param order here, because it's the most efficient way. If you are calling a function where you don't know the correct param order in advance, then yes, you'll need to use reflection. But I would think that's fairly unlikely (passing an unknown params list into an unknown function sounds like a goldmine for hackers)
Here is a library which does the argument resolving for a given function/method: ArgumentsResolver.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Render a variable during creation of anonymous PHP function
I am still quite new with PHP and this bothers me:
class Controller {
...
...
function _activateCar() {
$car_id = $this->data['car']->getId();
// $car_id == 1
$active_car = array_filter($this->data['cars'], function($car){
// $car_id undefined
return $car->getId() == $car_id;
});
}
...
...
}
Why can't the function inside array_filter access the $car_id variable? Keeps saying undefined.
Is there an other way to make $car_id accessible than to make a $_GET['car_id'] = $car_id;? Using the global keyword didn't help.
You need to add use($car_id) to your anonymous function, like so:
$active_car = array_filter($this->data['cars'], function($car) use($car_id){
// $car_id undefined
return $car->getId() == $car_id;
});
Anonymous functions can import select variables with the use keyword:
$active_car = array_fiter($this->data['cars'],function($car) use ($car_id) {
return $car->getId() == $car_id;
});