Specific php functionality - php

My team lead some time ago asked this question, which I didn't understood:
Implement function calc()
Please, implement function calc so code below works:
$sum = function($a, $b) { return $a + $b; };
calc(5)(3)(2)($sum); // 10
calc(1)(2)($sum); // 3
calc(2)(3)('pow'); // 8
So, can someone explain me what is it, and maybe some link on this functionality

The following will satisfy your example use:
<?php
function calc($input)
{
static $args = [];
if(is_callable($input)) {
$carry = array_shift($args);
$result = array_reduce($args, $input, $carry);
$args = []; // Clear the arguments.
return $result;
} else {
$args[] = $input; // Add arguments to the stack.
return __FUNCTION__;
}
}
$sum = function($a, $b) {
return $a + $b;
};
echo
calc(5)(3)(2)($sum), "\n",
calc(1)(2)($sum), "\n",
calc(2)(3)('pow'), "\n",
calc(5)(2)(2)('pow');
Output:
10
3
8
625
Explanation:
When calc is called with a single argument (that is not a callable), the input is pushed to an array and the name of the function, here 'calc', is returned.
calc(2)(3) will add 2 to the static array (this will persist between subsequent function calls), and return the function name. So this becomes calc(3), where the previous call has the side effect of storing 2 in $args.
If the argument passed is a callable. array_reduce will pass pairs of arguments from $args left to right to the callable, seeding subsequent calls with the result of each iteration.
array_reduce([1,2,3], 'pow', $initial) is similar to the following:
$result = pow($initial, 1);
$result = pow($result, 2);
$result = pow($result, 3);
However we need to use array_shift to remove the first item from the $args array as a seed for the first iteration of the pow call:
So that becomes array_reduce([2,3], 'pow', 1).
We then clear the argument list, otherwise subsequent calls to calc will use these arguments again, and the result of the array_reduce is returned.

You could have it as a calc function that takes a value and:
if it's a not a function, adds it to a buffer array, then return the function itself,
if it's a function, calls that function subsequently on every value of that buffer.
So if we take calc(6)(3)($sum):
calc(6) call will add 6 to the buffer array then return the calc function,
(3) will therefore pass 3 as a param to that same calc function that was just returned, therefore adding 3 to the buffer and returning the calc
function again,
finally, ($sum) will generate a call to that $sum function, passing it every value from the buffer (therefore, 3 then 6), reducing it into the final result.
Code:
function calc($value_or_function, array $buffer = [])
{
// If the argument is callable (a function), check that the buffer has
// at least one value and call this function subsequently on each value,
// reducing it into a final value
if (is_callable($value_or_function)) {
if (count($buffer) === 0) {
throw new \InvalidArgumentException('Not enough parameters.');
}
return array_reduce(array_slice($buffer, 1), $value_or_function, $buffer[0]);
}
// Otherwise (not a callable arg), add it to the buffer and return the
// function itself so that its result can be chain-called
return static function ($otherValue) use ($buffer, $value_or_function) {
return calc($otherValue, array_merge($buffer, [$value_or_function]));
};
}
// Example usage
$sum = function ($a, $b) { return $a + $b; };
echo calc(5)(4)(3)($sum), PHP_EOL;
echo calc(5)(2)(2)('pow');
Additional notes:
this is a decent exercise but probably a bad idea to have in a real codebase, this is quite unintuitive, the function does too many things, doesn't have strictly typed params, etc.,
those inline comments are a bit much for real code (they're that detailed for explanation purposes).
Demo: https://3v4l.org/AoKJO

Related

PHP variable packing and unpacking

I have a function that is used in Stripe PHP that requires PHP 5.6. I am running it on a server that has PHP 5.5.9 and giving me some trouble. The function is:
protected function buildPath($basePath, ...$ids)
{
foreach ($ids as $id) {
if (null === $id || '' === \trim($id)) {
$msg = 'The resource ID cannot be null or whitespace.';
throw new \Stripe\Exception\InvalidArgumentException($msg);
}
}
return \sprintf($basePath, ...\array_map('\urlencode', $ids));
}
I understand that the elipses(...) means it is variable packing. but when I try to convert it to something PHP 5.5.9 can use, using the below, it does not work:
protected function buildPath($basePath, pack($ids))
{
foreach ($ids as $id) {
if (null === $id || '' === \trim($id)) {
$msg = 'The resource ID cannot be null or whitespace.';
throw new \Stripe\Exception\InvalidArgumentException($msg);
}
}
return \sprintf($basePath, ...\array_map('\urlencode', $ids));
}
... in PHP can be used for two things:
Array unpacking, when calling a function, or populating another array. Note that this is not related to the unpack function, which is about handling binary data, but means "turn the items of this array into separate arguments to the function", or "... separate items of the final array".
Collecting variadic arguments - that is, a variable length argument list - when declaring a function. This is close to the reverse of "unpacking", but I've never heard it called "packing". Again, the pack function is completely unrelated (although, by coincidence, it is itself a variadic function). The effect is to take any number of arguments passed to the function and turn them into an array.
The example you show uses both features.
For the function signature, it is using variadic arguments. As noted on the manual page linked earlier:
Note: It is also possible to achieve variable-length arguments by using func_num_args(), func_get_arg(), and func_get_args() functions.
So, in all supported versions of PHP (5.5 has been unsupported for over 5 years; I hope you're paying someone for long-term-support security patches!), you can define the following function:
function example($normalArg, ...$variadicArgs) {
var_dump($variadicArgs);
}
and call it like this:
example('normal'); // $variadicArgs = []
example('normal', 1); // $variadicArgs = [1]
example('normal', 1, 2); // $variadicArgs = [1,2]
example('normal', 1, 2, 3); // $variadicArgs = [1,2,3]
In ancient versions of PHP before the ... notation was added, you had to instead declare the function with only the normal arguments, collect all the passed arguments by calling func_get_args, and skip over the "normal" ones. For example:
function example($normalArg) {
$allArgs = func_get_args();
$variadicArgs = array_slice($allArgs, 1);
var_dump($variadicArgs);
}
So in your case, the function could begin:
protected function buildPath($basePath)
{
$ids = \array_slice(\func_get_args(), 1);
Later in the function, it is using array unpacking. The only way to achieve this in ancient versions of PHP is using call_user_func_array, which takes a "callable" (which in simple cases can just be a function name as a string), and an array of arguments to pass to it. Again, you'll need to construct the full list of arguments, for instance using array_merge:
$fixedArgs = [$basePath];
$dynamicArgs = \array_map('\urlencode', $ids);
$allArgs = \array_merge($fixedArgs, $dynamicArgs);
return \call_user_func_array('\sprintf', $allArgs);
Or all on one line:
return \call_user_func_array('\sprintf', \array_merge([$basePath], \array_map('\urlencode', $ids)]);
As it happens, the particular function called here is sprintf, which has a variant called vsprintf ("v" for "vector") which takes an array of parameters instead of multiple separate arguments, so for this particular case you can use that:
return \vsprintf($basePath, \array_map('\urlencode', $ids));
In php 5.5.9 it can be written like this and is called Variadic function:
protected function buildPath($basePath)
{
$ids = func_get_args();
array_shift($ids);
foreach ($ids as $id) {
if (null === $id || '' === \trim($id)) {
$msg = 'The resource ID cannot be null or whitespace.';
throw new \Stripe\Exception\InvalidArgumentException($msg);
}
}
return \sprintf($basePath, ...\array_map('\urlencode', $ids));
}

How can a function call itself in PHP?

I am new with Laravel and PHP so I decide to see the core code and try to read it a little, but when I reached this part, I am confused! how does this function works? $this->getAlias($this->aliases[$abstract]); can a function call itself? wouldn't it be looping?
protected function getAlias($abstract)
{
if (! isset($this->aliases[$abstract])) {
return $abstract;
}
return $this->getAlias($this->aliases[$abstract]);
}
thank you
You may want to read about recursive functions.
A recursive function is a function that calls itself
This function takes some argument and checks if it has an alias. If it does, it calls itself again and checks if found alias has an alias etc.
These are called recursive functions... Which means, a function can call itself until the final condition for the expected output is reached.
A simple example for this would be... Multiplication of 2 until the sum reaches 100.
public function multiplication($a, $sum = 0, $times = 0) {
if($sum == 100) {
return $times;
}
$sum += $a;
$times++;
return multiplication($a, $sum, $times);
}
echo multiplication(2);
Output will be
50
In the function written in the question, it is trying to check if all the abstract value passed as param is set for that current class or not.
Hope you are now clear of the concept. :)

Is there a more elegant way to pass a function to another function in PhP?

It can be done by passing the function name in a string PHP pass function as param then call the function?
Well that is very crude.
No type checking
If I refactor the function name the string containing the variable need to be fixed too manually. If we have a typo it won't be checked on compile time.
It's not like in vb.net where we have addressOf operator.
Is this really the only way to do this in PhP?
I mean the lamda function seems more sane. At least the variable we pass is really a functio6 and not a string.
Am I wrong here?
Is the right way to do this is to use lambda?
Or is there any other way?
I can use closures like this
function getSelectedElements($textFile)
{
$standardfuncline2= function (&$arout,$line)
{
standardfuncline1 ($arout,$line);
};
$result = getSelectedElementsCustomFunc ($textFile,$standardfuncline2);
return $result;
}
instead of
$result = getSelectedElementsCustomFunc ($textFile,"standardfuncline1");
That seems to be more proven with all type checking and stuffs. However, kind of too long isn't it?
You can define your function as a closure, i.e. an anonymous function which can be assigned to a variable or passed as a function argument directly. The following example is taken from the PHP docs on callables:
Callback example using a Closure
<?php
// Our closure
$double = function($a) {
return $a * 2;
};
// This is our range of numbers
$numbers = range(1, 5);
// Use the closure as a callback here to
// double the size of each element in our
// range
$new_numbers = array_map($double, $numbers);
print implode(' ', $new_numbers);
?>
The above example will output:
2 4 6 8 10
More variants on the above can be found in the PHP documentation on anonymous functions.
When referencing an existing function
There is no such solution for functions that are defined in the usual way, but you can encapsulate them as a Callable:
// Your already existing function:
function myFunc($arg) {
echo "running myFunc with '$arg'.";
}
// The new Callable wrapper for it:
$myFunc = function ($arg) {
myFunc($arg);
};
// Calling it (same as in first solution)
call_user_func($myFunc, 'test');
You can sure do some Type-Hinting even when using call_user_func() like so:
/**
* #var $arrActions array
* #return mixed
*/
function doSomething(array $arrActions) { // TYPE HINT ARRAY
$output = "";
if(is_array($arrActions)) {
foreach ($arrActions as $action) {
$output .= "Have you already performed Action Nr. $action ?\n";
}
}
return $output;
}
// CALL WITH ARRAY AS ARGUMENT..
var_dump( call_user_func('doSomething', ["one", "two", "three"]) );
// PRODUCES:
string 'Have you already performed Action Nr. one ?
Have you already performed Action Nr. two ?
Have you already performed Action Nr. three ?
' (length=134)
// CALL WITH STRING AS ARGUMENT..
var_dump( call_user_func('doSomething', "one"]) );
// PRODUCES:
Fatal error: Uncaught TypeError: Argument 1 passed to doSomething() must be of the type array, string given....

Method chaining without final method

I came across plenty of examples of method chaining in PHP, but couldn't find anything about this one, so I'm asking for help you guys;)
My problem is - can I in some way find out if the method in chain is the last one? In most cases people are using some sort of final method (execute, send,..) to tell when the chain ends and return the corresponding result. But I wonder if there is some hidden magic method or technique than can check all the methods in chain and detect if there is no next method?
Without final method it works fine for strings (in the very simple example), but not if I want to return array.
Here is my snippet :
class Chain {
private $strArray;
function __call($name, $args) {
$this->strArray[] = $args[0];
return $this;
}
function __toString() {
return implode('-', $this->strArray);
}
}
// example 1
$c = new Chain();
$x = $c->foo('hi')->bar('stack'); // need array('hi', 'stack')
// example 2
$c = new Chain();
$x = $c->foo('hi')->bar('stack')->foobar('overflow'); // need array('hi', 'stack', 'overflow')
// example 3
$c = new Chain();
echo $c->foo('hi')->foobar('overflow'); // prints 'hi-overflow'
// example 4
$c = new Chain();
echo $c->foo('hi')->bar('stack')->foobar('overflow'); // prints 'hi-stack-overflow'
You see, when I want to print the result of chain, I can modify the result in the __toString method, but what if I need an array (example 1, 2)? Is there any way to achieve that without calling some additional "final" method?
Thanks a lot for help and let me know if you need more info.
EDIT: After feedback from #bandi I tried to extend ArrayObject like this.
class Chain extends ArrayObject {
function __call($name, $args) {
$this->append($args[0]);
return $this;
}
function __toString() {
return implode('-', $this->getIterator()->getArrayCopy());
}
}
// returned ref. to object, works fine in loop or accessing offset
$obj = new Chain;
$x = $obj->foo('hi')->bar('stack')->foobar('overflow'); // need array('hi', 'stack', 'overflow')
foreach ($x as $y) {
echo $y, "\n";
}
var_dump($x[0], $x[1], $x[2]);
// returned String
$c = new Chain;
echo $c->foo('hi')->foobar('overflow'); // prints 'hi-overflow'
It does what I wanted, however I don't feel so good about the $this->getIterator()->getArrayCopy() part. Is there some simple way of accessing the array (internally in ["storage":"ArrayObject":private])?
Thanks
Method chaining is using the return value of a function, in this case this is the reference to the object. Predicting the use of a returned value is generally not possible.
You have to tell the called method that you want to do something different. You can use the second argument for this, e.g. you return a different result if the second argument is defined. The other option might be to modify the class so that it behaves like an array except if it is printed.

working of callback function

while reading abt array_filter() from php manual,came to face example to demostrate
the same function using callback function as given below
<?php
function odd($var)
{
// returns whether the input integer is odd
return($var & 1);
}
function even($var)
{
// returns whether the input integer is even
return(!($var & 1));
}
$array1 = array("a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5);
$array2 = array(6, 7, 8, 9, 10, 11, 12);
echo "Odd :\n";
print_r(array_filter($array1, "odd"));
echo "Even:\n";
print_r(array_filter($array2, "even"));
?>
can you please help me to know how actually calback function calling,actual parameter pass,working?
any link to demostrate about callback wld be great help.
In the two given examples, array_filter will go over the values in the passed array and send each value in it to the callback function (odd or even). The callback function will then inspect the value to see whether it is odd or even and return TRUE or FALSE. If it returns FALSE, the value is filtered from the array.
The easiest way to find out what your function is passing to your callback is to supply a callback that prints the passed arguments, e.g.
array_filter($anArray, function() { var_dump(func_get_args()) });
Callbacks are described in detail at
http://de.php.net/manual/en/language.pseudo-types.php#language.types.callback
Imagine you have a function like this:
function getNumbersDivisibleBy3($arr)
{
$threes = array();
foreach($arr as $val)
{
if($val % 3 == 0)
{
$threes[] = $val;
}
}
return $threes
}
This function filters out all the numbers divisible by three from an array and returns them as another array.
Now imagine another function:
function GetWordsStartingWithC($arr)
{
$cs = array();
foreach($arr as $word)
{
if($word[0] == 'C')
{
$cs[] = $word;
}
}
return $cs;
}
This function filters out all the words that start with C from an array of words and returns them another array.
If you look at the above functions, their meta function (as it were) can be explained as "This functions filters out all the items in an array that satisfies a condition and returns them as another array."
So instead of having to write the same boiler plate code to iterate through a list and filter out all elements that match, the PHP developers have written a function that takes an array and a string that is a function name.
In other languages, such as C#, instead of a string that is a function name, you actually pass in an object called a delegate, which is a pointer or reference to a function. But in PHP they have ways of figuring out which function you mean by the name you pass in. I don't know what those are.
So the array_filter function could look something like this (it won't as it's probably not written in PHP)
function array_filter($arr, $callbackname)
{
$result = array();
foreach($arr as $item)
{
if(call_user_func($callbackname, $item))
{
$result[] = $item;
}
}
return $result;
}
In that function you can see how similar it is to the previous two, but instead of a predefined condition, it calls back (using the call_user_func() function) the function to be used via the name you passed in and applies it to each item in the array by using each item as a parameter for the function.
So you can reduce the amount of code you write by using array_filter because you don't have to write the boiler plate iteration code, just the conditional function you need to filter on.
A callback function is a function that it "called back" by another one. In the case of array_filter() the callback is invoked for every element of the array, and that element is the argument passed to it. You don't control what argument are passed, that's up the the main function you're using.
So you basically say to array_filter(): please run through this array and apply this function named "odd" to every element; this function will return a boolean value so you know what to keep and what to discard.

Categories