Define arity of an anonymous function without code generation - php

It is possible to determine how many arguments a function accepts by using reflection.
I want to be able to define a function compose that performs function composition. That is to say, compose($f, $g) should produce a new function that returns $f($g($x)).
I have a sample implementation here:
function compose()
{
$fns = func_get_args();
$prev = array_shift($fns);
foreach ($fns as $fn) {
$prev = function ($x) use ($fn, $prev) {
$args = func_get_args();
return $prev(call_user_func_array($fn, $args));
};
}
return $prev;
}
When composing $f and $g, $g may have an arity higher than 1. Which means it can take more than one argument. Thus, the function returned by compose($f, $g) may also take more than one argument -- it takes exactly the same arguments as $g.
The problem with this implementation is that there is no way to control the exposed arity of what compose returns. In this case it is always 1, because of the function ($x) .... When trying to determine the arity using reflection, it will always return 1 instead of that of $g.
Is there a way to change the amount of arguments of an anonymous function seen by PHP's reflection system, without using eval and other code generation techniques?

The moment you introduce func_get_args() into a function should invalidate any hope of being able to determine its true arity. At that point, the arity is really only defined by the function's logic, and cannot be determined by reflection or static code analysis.
I've written a compose-like implementation before, but it just assumed that the functions you are composing both have an arity of 1.

Here is an ugly solution as it does not work with all number of parameters (or you end up with tons of case stuff), but it does not rely on eval:
function compose($f, $g)
{
switch(getReflectiveArity($g)) {
case 1:
return function($x) use ($f, $g) {
return $f($g($x));
};
break;
case 2:
return function($x, $y) use ($f, $g) {
return $f($g($x));
};
break;
case 3:
return function($x, $y, $z) use ($f, $g) {
return $f($g($x, $y, $z));
};
break;
/* ... */
default:
throw new RuntimeException();
}
}

My proposed solution to this would be to introduce a custom convention for specifying the arity using a custom property, defined on an object that wraps the closure.
Like this:
class CustomArityFunction
{
public $f;
public $arity;
function __construct(callable $f, $arity)
{
$this->f = $f;
$this->arity = $arity;
}
function __invoke()
{
return call_user_func_array($this->f, func_get_args());
}
}
// define function
$f = function () { ... };
return new CustomArityFunction($f, $n);
// determine arity
$arity = ($f instanceof CustomArityFunction) ? $f->arity : getReflectiveArity($f);
The major downside of this solution is that the consuming code needs to be aware of the convention.
It is however the cleanest way of doing this that I could come up with.
Note: The wrapper is needed because PHP does not allow assigning properties to closures. Thanks to #nikic for pointing that out.

Based upon How can I dynamically check the number of arguments expected of an anonymous function in PHP?
is the following piece of code which works on php >= 5.3
http://3v4l.org/6KPFN
Update: Just reread the question ... this is probably BS

Related

How to define and code custom unit-test in raw PHP?

I am using some special PHP framework. I can't use any unit-test frameworks by some reasons like PHPunit or codeception. So i need to write my custom code to achieve that. Is there any examples could finish the job?
Can i use this method instead of using framework?
public function testFailure()
{
$a = 1; $b = 0;
if($a !=== b){
//throw exception here
}
}
Instead-
public function testFailure()
{
$this->assertEquals(1, 0); //return false
}
The absolutely easiest way would be pretty much what you wrote above (although the code is not really valid). Throw an exception on assertions and you have a valid way of unit testing!
Now, I would think that you could probably use something like phpunit weather or not you are using some custom code, but I won't push on that more than letting you know.
Also:
!=== is invalid, !== would be more correct!
Further on, I'd recommend that you create some type of static or global methods for your assertions instead of the above, that way you can easily re-use the exception throwing code instead of writing the same over and over:
// assert.php
class Assert {
public static function isEqual($a, $b) {
if ($a != $b) {
throw new MyAssertionException('Not equal!');
}
return true;
}
public static function isSame($a, $b) {
if ($a !== $b) {
throw new MyAssertionException('Not same!');
}
return true;
}
}
---
// test.php
include_once 'assert.php';
Assert::isEqual(1, 2);

PHP use of anonymous functions

So I'm really confused about anonymous functions in PHP, I want to know if anonymous functions are mainly used as a matter of taste or coding style.
I'm asking this because you can achieve the same result without a callback function and less code.
So here is some test code:
$output = 10;
$people = (new People(new John));
//VERSION 1 ANONYMOUS FUNCTION
$people->run(function ($value) use(&$output){
$output = $output + $value;
});
var_dump($output); //RESULT => 20
//VERSION 2 WITHOUT ANONYMOUS FUNCTION
var_dump($people->run() + $output); //RESULT => 30
You can run and see the full code here:
https://www.tehplayground.com/IhWJJU0jbNnzuird
<?php
interface HumanInterface
{
public function hello();
}
class People
{
protected $person;
protected $value;
public function __construct(HumanInterface $person)
{
$this->person = $person;
return $this;
}
public function run(callable $callback = null, $name = null)
{
$this->value = 10;
if(is_callable($callback)) {
return call_user_func($callback, $this->value);
}
return $this->value;
}
}
class John implements HumanInterface
{
public function hello()
{
return 'hi i am john';
}
}
$output = 10;
$people = (new People(new John));
$people->run(function ($value) use(&$output){
$output = $output + $value;
});
var_dump($output);
var_dump($people->run() + $output);
So my question is: why use an anonymous function? Is it a matter of
personal choice?
Anonymous functions or „Closures“ are very useful if it is used as a one-time callback. If you use PHP's usort-method for example. The second parameter can be a Closure. So instead of writing a named function which is used once and then never again you use a Closure.
IMHO this is the only way to use Closures: as a callback.
Anonymous functions are useful to pass around for later execution or to other code accepting functions. Using them can dramatically reduce the code needed to do things.
Imagine you have a UserCollection object that uses a generic Collection underneath. You want to reduce the UserCollection to just the Users from a certain country. So you could add a method findByCountry() on the UserCollection:
public function findByCountry($country) : UserCollection {
$subset = new UserCollection;
foreach ($this->users as $user) {
if ($user->country === $country) {
$subset->add($user);
}
}
return $subset;
}
This is all fine, but additional finder methods will all do the same: iterate and collect into the subset with only the criteria being different. So a lot of boilerplate code.
You can separate the boilerplate from the criteria easily by adding a method find(callable $callback) on the underlying Collection, like this:
public function find(callable $criteria) : Collection {
$subset = new Collection;
foreach ($this->users as $user) {
if ($criteria($user)) {
$subset->add($user);
}
}
return $subset;
}
This is a generic finder. Now your code in the UserCollection will only contain the actual criteria:
public function findByCountry($country): UserCollection {
return $this->subset(function(User $user) {
return $user->country === $country;
});
}
private function subset($criteria): UserCollection {
return new UserCollection($this->allUsers->find($criteria));
}
By separating the criteria from the boilerplate, it's much easier to grasp that you are trying to find users by country. There is no iteration code distracting from the actual criteria. So it becomes easier to understand and less effort to write. Also, you cannot accidentally mess up the iteration because it's defined elsewhere.
When using anonymous functions like this, they are very similar to using the Strategy Pattern or a FilterIterator. The notable difference being that you are creating them on the fly.
Note that you have to differentiate between Lambdas and Closures. I deliberately ignored the difference for this answer.

PHP modify code to avoid anonymous functions

I've found some solutions to a sorting problem I've been having, but the code uses anonymous functions in PHP. Im using version 5.2.17 and I believe anonymous functions are not supported.
How would I change the following blocks of code so I can use them in PHP 5.2.17
$keys = array_flip($order);
usort($items, function($a, $b) use($keys)
{
return $keys[$a['id']] - $keys[$b['id']];
});
from PHP sort multidimensional array by other array
And
$sorted = array_map(function($v) use ($data) {
return $data[$v - 1];
}, $order);
from PHP - Sort multi-dimensional array by another array
UPDATE:
One of the problems is I'm not sure how the variables $a, $b and $v are used. So I'm not sure how to create normal functions, thus bypassing the anon functions.
Both of the anonymous functions make use of the use clause to pass variables into the local scope.
You can achieve the same with object methods in which the objects have those variables as properties.
Inside the object method you then can access these.
$sorted = array_map(function($v) use ($data) {
return $data[$v - 1];
}, $order);
An exemplary mapping object then could look like:
class MapObj
{
private $data;
public function __construct($data) {
$this->data = $data;
}
public function callback($v) {
return $this->data[$v - 1];
}
}
As you can see it has the same functionality but just written in PHP 5.2 syntax.
And it's usage:
$map = new MapObj($data);
$callback = array($map, 'callback');
$sorted = array_map($callback, $order);
And that's how it works. Callbacks for object methods are always written in form of an array with two members, the first one is the object instance, and the second one is the name of the object method.
Naturally you can extend this an put the mapping function into the mapping object, so it's more straight forward:
class MapObj
{
...
public function map(array $order) {
$callback = array($this, 'callback');
return array_map($callback, $order);
}
}
New usage:
$map = new MapObj($data);
$sorted = $map->map($order);
As you can see this might make the usage a bit more straight forward. I must admit, my method naming is not really brilliant here, so I leave some room for your improvements.
Another benefit is, you can make the visibility of the callback method private then.
The situation with passing the data to work with in the callback as a parameter to the mapping function. That is because you wrote you already have a class that you want to make use of, but you can not touch the constructor. So the given example is a bit short.
Here is another example without using the constructor, I removed it:
class MyObj
{
private $data;
private function callback($v) {
return $this->data[$v - 1];
}
public function map($order, $data) {
$callback = array($this, 'callback');
$this->data = $data;
return array_map($callback, $order);
}
}
As you can see, the constructor is not needed any longer to pass the $data, but instead it's just passed into the map() method as an additional parameter. Usage:
$myObj = new MyObj(....); // somewhere.
// later on:
$myObj->map($order, $data);
// could be also:
$this->map($order, $data);
As you can see, how you set the private member variable is up to you. Do what fits the job.
What you have here is a closure over $data -- it's not 100% possible to rewrite it without an anonymous function. Here's the closest possible approximation:
function _array_sort_callback($a, $b) {
global $_array_sort_callback__keys;
return $_array_sort_callback__keys[$a['id']] - $_array_sort_callback__keys[$b['id']];
}
... {
$keys = array_flip($order);
global $_array_sort_callback__keys;
$_array_sort_callback__keys = $keys;
usort($items, "_array_sort_callback");
}
Note that I've prefixed the name of the global to try to avoid a collision. Both the function name and the global name need to be unique within your application.
Also, keep in mind that PHP 5.2.17 is obsolete and unsupported. You should migrate off of it as soon as possible.
If you want to mimic a closure, where you snapshot variables at a specific time, you can use a simple base class to serve as a container for the values, and then just define sub classes to implement the comparison logic.
Untested
// base class exists purely to capture the value of some variables at instantiation time
// kinda like a closure
class VarCapture {
protected $vars;
function __construct($vars) {
$this->vars = $vars;
}
}
class ItemComparer extends VarCapture {
function compare($a, $b) {
$keys = $this->vars['keys'];
return $keys[$a['id']] - $keys[$b['id']];
}
}
class PluckMapper extends VarCapture {
function pluck($v) {
$data = $this->vars['data'];
return $data[$v - 1];
}
}
$keys = array_flip($order);
$ic = new ItemComparer(compact('keys'));
$callable = array($ic, 'compare');
usort($items, $callable);
$pm = new PluckMapper(compact('data'));
$callable = array($mp, 'pluck');
$sorted = array_map($callable, $order);
Note that I made use of php's callback psuedo type
http://php.net/manual/en/language.types.callable.php
You can also re-write it into pre-5.3 anonymous functions, a la create_function(). Although create_function() functions don't normally act as closures, you can use some tricks (without using global variables) to make them work as closures in some limited circumstances. You encode the closed-over variables directly into the source of the function. The limitations are that data only goes one-way -- in; closed-over variables can only be "simple" data types, like numbers, strings, and arrays; and functions created with create_function are never deallocated, leaking memory; plus it is not very efficient. But I think it is sufficient for your example (assuming you only use arrays and strings and such).
$keys = array_flip($order);
usort($items, create_function('$a,$b', '$keys = '.var_export($keys,true).';
return $keys[$a["id"]] - $keys[$b["id"]];
'));
and
$sorted = array_map(create_function('$v', '$data = '.var_export($data,true).';
return $data[$v - 1];
'), $order);
The more general pre-5.3 solution, though, is to use an object and method as the closure, as in hakra's answer.

PHP call_user_func & $class->$func()

RT
function 1 :
$class->$func()
function 2:
//Simple callback
call_user_func($func)
//Static class method call
call_user_func(array($class,$func))
//Object method call
$class = new MyClass();
call_user_func(array($class, $func));
Is there a difference? I want to see the sourcecode(https://github.com/php/php-src) should we do?
call_user_func_array is very slow performance-wise, that's why in many cases you want to go with explicit method call. But, sometimes you want to pass arbitrary number of arguments passed as an array, e.g.
public function __call($name, $args) {
$nargs = sizeof($args);
if ($nargs == 0) {
$this->$name();
}
elseif ($nargs == 1) {
$this->$name($args[0]);
}
elseif ($nargs == 2) {
$this->$name($args[0], $args[1]);
}
#...
// you obviously can't go through $nargs = 0..10000000,
// so at some point as a last resort you use call_user_func_array
else {
call_user_func_array(array($this,$name), $args);
}
}
I'd go with checking $nargs up to 5 (it's usually unlikely that a function in PHP accepts more than 5 arguments, so in most cases we will call a method directly without using call_user_func_array which is good for performance)
The result of $class->method($arg) is the same as call_user_func_array(array($class,'method'), array($arg)), but the first one is faster.

Same named function with multiple arguments in PHP

I started off OOP with Java, and now I'm getting pretty heavy into PHP. Is it possible to create multiples of a function with different arguments like in Java? Or will the interpreted / untyped nature of the language prevent this and cause conflicts?
Everyone else has answers with good code explanations. Here is an explanation in more high level terms: Java supports Method overloading which is what you are referring to when you talk about function with the same name but different arguments. Since PHP is a dynamically typed language, this is not possible. Instead PHP supports Default arguments which you can use to get much the same effect.
If you are dealing with classes you can overload methods with __call() (see Overloading) e.g.:
class Foo {
public function doSomethingWith2Parameters($a, $b) {
}
public function doSomethingWith3Parameters($a, $b, $c) {
}
public function __call($method, $arguments) {
if($method == 'doSomething') {
if(count($arguments) == 2) {
return call_user_func_array(array($this,'doSomethingWith2Parameters'), $arguments);
}
else if(count($arguments) == 3) {
return call_user_func_array(array($this,'doSomethingWith3Parameters'), $arguments);
}
}
}
}
Then you can do:
$foo = new Foo();
$foo->doSomething(1,2); // calls $foo->doSomethingWith2Parameters(1,2)
$foo->doSomething(1,2,3); // calls $foo->doSomethingWith3Parameters(1,2,3)
This might not be the best example but __call can be very handy sometimes. Basically you can use it to catch method calls on objects where this method does not exist.
But it is not the same or as easy as in Java.
Short answer: No. There can only be one function with a given name.
Longer answer: You can do this by creating a convoluted include system that includes the function with the right number of arguments. Or, better yet, you can take advantage of PHP allowing default values for parameters and also a variable amount of parameters.
To take advantage of default values just assign a value to a parameter when defining the function:
function do_something($param1, $param2, $param3 = 'defaultvaule') {}
It's common practice to put parameters with default values at the end of the function declaration since they may be omitted when the function is called and makes the syntax for using them clearer:
do_something('value1', 'value2'); // $param3 is 'defaultvaule' by default
You can also send a variable amount of parameters by using func_num_args() and func_get_arg() to get the arguments:
<?php
function dynamic_args() {
echo "Number of arguments: " . func_num_args() . "<br />";
for($i = 0 ; $i < func_num_args(); $i++) {
echo "Argument $i = " . func_get_arg($i) . "<br />";
}
}
dynamic_args("a", "b", "c", "d", "e");
?>
Following isn't possible with php
function funcX($a){
echo $a;
}
function funcX($a,$b){
echo $a.$b;
}
Instead do this way
function funcX($a,$b=null){
if ($b === null) {
echo $a; // even though echoing 'null' will display nothing, I HATE to rely on that
} else {
echo $a.$b;
}
}
funcX(1) will display 1, func(1,3) will display 13
Like everyone else said, it's not supported by default. Felix's example using __call() is probably the best way.
Otherwise, if you are using classes that inherit from each other you can always overload the method names in your child classes. This also allows you to call the parent method.
Take these classes for example...
class Account {
public function load($key,$type) {
print("Loading $type Account: $key\n");
}
}
class TwitterAccount extends Account {
public $type = 'Twitter';
public function load($key) {
parent::load($key,$this->type);
}
}
Then you can call them like so...
$account = new Account();
$account->load(123,'Facebook');
$twitterAccount = new TwitterAccount();
$twitterAccount->load(123);
And your result would be...
Loading Facebook Account: 123
Loading Twitter Account: 123
No this isn't possible, because PHP cannot infer from the arguments which function you want (you don't specify which types you expect). You can, however, give default values to arguments in php.
That way the caller can give different amounts of arguments. This will call the same function though.
Example is:
function test($a = true)
This gives a default of true if 0 arguments are given, and takes the calling value if 1 argument is given.
I know it's a bit old issue, but since php56 you can:
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
ref: http://php.net/manual/en/functions.arguments.php
Overloading is not possible in PHP but you can get around it to some extend with default parameter values as explained in other responses.
The limit to this workaround is when one wants to overload a function/method according to the parameter types. This is not possible in PHP, one need to test the parameter types yourself, or write several functions. The functions min and max are a good example of this : if there is one parameter of array type it returns the min/max of the array, otherwise it returns the min/max of the parameters.
I had the idea of something like:
function process( $param1 , $type='array' ) {
switch($type) {
case 'array':
// do something with it
break;
case 'associative_array':
// do something with it
break;
case 'int_array':
// do something with it
break;
case 'string':
// do something with it
break;
// etc etc...
}
}
I have got 2 methods, getArrayWithoutKey which will output all the entries of an array without supplying any key value. The second method getArrayWithKey will output a particular entry from the same array using a key value. Which is why I have used method overloading there.
class abcClass
{
private $Arr=array('abc'=>'ABC Variable', 'def'=>'Def Variable');
public function setArr($key, $value)
{
$this->Arr[$key]=$value;
}
private function getArrWithKey($key)
{
return $this->Arr[$key];
}
private function getArrWithoutKey()
{
return $this->Arr;
}
//Method Overloading in PHP
public function __call($method, $arguments)
{
if($method=='getArr')
{
if(count($arguments)==0)
{
return $this->getArrWithoutKey();
}
elseif(count($arguments)==1)
{
return $this->getArrWithKey(implode(',' , $arguments));
}
}
}
}
/* Setting and getting values of array-> Arr[] */
$obj->setArr('name', 'Sau');
$obj->setArr('address', 'San Francisco');
$obj->setArr('phone', 7777777777);
echo $obj->getArr('name')."<br>";
print_r( $obj->getArr());
echo "<br>";

Categories