PHP - Passing functions with arguments as arguments - php

I have several interchangeable functions with different numbers of arguments, for example:
function doSomething1($arg1) {
…
}
function doSomething2($arg1, $arg2) {
…
}
I would like to pass a certain number of these functions, complete with arguments, to another handling function, such as:
function doTwoThings($thing1, $thing2) {
$thing1();
$thing2();
}
Obviously this syntax is not correct but I think it gets my point across. The handling function would be called something like this:
doTwoThings(‘doSomething1(‘abc’)’, ‘doSomething2(‘abc’, ‘123’));
So the question is, how is this actually done?
From my research it sounds like I may be able to "wrap" the "doSomething" function calls in an anonymous function, complete with arguments and pass those "wrapped" functions to the "doTwoThings" function, and since the anonymous function doesn't technically have arguments they could be called in the fashion shown above in the second code snippet. The PHP documentation has me confused and none of the examples I'm finding put everything together. Any help would be greatly appreciated!

you could make use of call_user_func_array() which takes a callback (eg a function or class method to run) and the arguments as an array.
http://php.net/manual/en/function.call-user-func-array.php
The func_get_args() means you can feed this funciton and arbitary number of arguments.
http://php.net/manual/en/function.func-get-args.php
domanythings(
array( 'thingonename', array('thing','one','arguments') ),
array( 'thingtwoname', array('thing','two','arguments') )
);
funciton domanythings()
{
$results = array();
foreach( func_get_args() as $thing )
{
// $thing[0] = 'thingonename';
// $thing[1] = array('thing','one','arguments')
if( is_array( $thing ) === true and isset( $thing[0] ) and is_callable( $thing[0] ) )
{
if( isset( $thing[1] ) and is_array( $thing[1] ) )
{
$results[] = call_user_func_array( $thing[0], $thing[1] );
}
else
{
$results[] = call_user_func( $thing[0] );
}
}
else
{
throw new Exception( 'Invalid thing' );
}
}
return $results;
}
This would be the same as doing
thingonename('thing','one','arguments');
thingtwoname('thing','two','arguments');

Related

How to write a function that could be called like func(a)(b)(c) in php?

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);
};
}

Check if the variables passed to a function is empty

Im working on a register function that will register users into the database.
I want a checker in that function that checks if any of the arguments are empty. I've simplified the problem, so this is not the retail look.
<?php
create_user($_POST["username"], $_POST["epost"]);
function create_user($username, $epost){
// Pull all the arguments in create_user and check if they are empty
// Instead of doing this:
if(empty($username) || empty($epost)){
}
}
Reason for making this is so i can simply add another argument to the function and it checks automatically that it isnt empty.
Shorted question:
How do I check if all the arguments in a function isnt empty?
function create_user($username, $epost){
foreach(func_get_args() as $arg)
{
//.. check the arg
}
}
You can use array_filter and array_map functions also.
For example create a function like below
<?php
function isEmpty( $items, $length ) {
$items = array_map( "trim", $items );
$items = array_filter( $items );
return ( count( $items ) !== (int)$length );
}
?>
the above function accepts two parameters.
$items = array of arguments,
$length = the number of arguments the function accepts.
you can use it like below
<?php
create_user( $_POST["username"], $_POST["epost"] );
function create_user( $username, $epost ) {
if ( isEmpty( func_get_args(), 2 ) ) {
// some arguments are empty
}
}
?>

Check for anonymous functions in PHP arrays?

How can we check for anonymous functions inside PHP arrays?
Example:
$array = array('callback' => function() {
die('calls back');
});
Can we then just simply use in_array, and to something like this:
if( in_array(function() {}, $array) ) {
// Yes! There is an anonymous function inside my elements.
} else {
// Nop! There are no anonymous function inside of me.
}
I'm experimenting with method chaining and PHP's Magic Methods, and I've come to the point where I provide some functions anonymously, and just want to check if they are defined, but I wish not to loop through the object, nor to use gettype, or anything similar.
You can filter the array by checking if the value is an instance of Closure:
$array = array( 'callback' => function() { die( 'callback'); });
$anon_fns = array_filter( $array, function( $el) { return $el instanceof Closure; });
if( count( $anon_fns) == 0) { // Assumes count( $array) > 0
echo 'No anonymous functions in the array';
} else {
echo 'Anonymous functions exist in the array';
}
Pretty much, just check if the element of the array is an instance of Closure. If it is, you have a callable type.
Nickb's answer is great for figuring out if it is an anonymous function, but you may also use is_callable to figure out if it is any type of function ( probably more safe to assume )
For example
$x = function() { die(); }
$response = action( array( $x ) );
...
public function action( $array ){
foreach( $array as $element )
if( is_callable( $element ) )
....
}

Smarter if statement and arrays is not working

I want to create a smarter way to create if statements. I'm writing a function to do this:
if ( ! function_exists( 'get_meta' ) ) {
function get_meta($i) {
$fname_name = array(
'copyright_text',
'about_name',
'archive_name',
'contact_name',
'lenguage_name',
'cc_name',
'about_link',
'archive_link',
'contact_link',
'lenguage_link',
'cc_link',
'about_editors_name',
'about_responsibility_name',
'about_joinus_name',
'about_editors_link',
'about_responsibility_link',
'about_joinus_link'
);
foreach( $fname_name as $fname )
include_once( get_option($fname));
if ( $i ) return $fname_name[$i];
}
}
But when this function is called, it returns this error:
Warning: include_once() [function.include]: Failed opening 'what' for inclusion (include_path='.;php\PEAR') in local\wp-content\themes\net\0.6\functions.php on line 398
Basically, just want to add get_option(''); to each array, to return for example:
get_option('copyright_text');
or even more specific, to return:
get_option('copyright_text', '');
FIXED:
Okay, I just fix this by myself, but I'm so grateful of any advice here.
Instead using foreach and include_once, I use an even more simple solution:
if ($i) return get_option($fname_name[$i], '');
else if ($i == 0) return get_option($fname_name[0], '');
use this
foreach( $fname_name as $fname ){
include_once( get_option($fname));
if ( $i ) return $fname;
}
This looks like you are creating a shortcut for writing accessor methods. You would do yourself some good to take a look at PHP's magic methods. Specifically pay attention to __get, __set, and __call.
http://php.net/manual/en/language.oop5.magic.php
In this case, what you are doing looks similiar to the following:
class myClass {
// This could be associated with whatever other data you are interested in
private $_meta = array(
'copyright_text',
'about_name',
'archive_name',
'contact_name',
'lenguage_name',
'cc_name',
'about_link',
'archive_link',
'contact_link',
'lenguage_link',
'cc_link',
'about_editors_name',
'about_responsibility_name',
'about_joinus_name',
'about_editors_link',
'about_responsibility_link',
'about_joinus_link'
);
public function __get($name) {
if (in_array($name, $this->_meta)) {
return $this->_meta[$name];
}
}
}

How to pass series of variables in function as array or regardless of their order?

I am sorry, that sounds like a noob question. I am trying to do this, maybe my question is not clear.
I want to be able to pass something like this:
make_thumbnail( array( 'width' => 60, 'height' => 40', 'title' => 'my image' ) );
Now the above line calls the function which already produces the thumbnails I have that no problem, but I want flexibility here. I mean my function has variables ordered like this:
function make_thumbnail($title,$width,$height) {
the code..
echo ...
}
Now you get what I want to do? I want to be able to pass the variables in any order.. they do not have to come in same order title, width, height.. i want to be able to specify the order when I call the function in template as I put in very first line.
I tried to make my question as clear as I can, but really could not find anything about it.
This sort of thing?
function make_thumbnail($myarray) {
$sometitle = $myarray["title"]
$somewidth = $myarray["width"]
$someheight = $myarray["height"]
}
Why not have the array as the function argument? e.g.
function make_thumbnail($argsArray) {
echo $argsArray['width'];
}
You can create variables within your function for each parameter
function make_thumbnail($argsArray) {
$width = $argsArray['width'];
$height = $argsArray['height'];
$title = $argsArray['title'];
// ...plug the rest of your original function here
}
Then your function will behave exactly the same, except you can pass in an array.
What you're asking for is a description of the Reflection syntax of PHP:
function callWithNamedParams( $funcName, array $args = null )
{
if( is_null( $args ) ) return $funcName();
$f = new ReflectionFunction($funcName);
$input = array();
foreach( $f->getParameters() as $param )
{
array_push( $input, #$args[ $param->getName() ] );
}
return call_user_func_array( $funcName, $input );
}
Use:
function myFunc( $foo, $bar )
{
echo "foo = $foo; Bar = $bar";
}
callWithNamedParams( "myFunc", array( "bar"=>1, "foo"=>2 ) );
You should get foo = 2; Bar = 1 as an output.
you need to define your logic to take any parameter as the one you want it to be. Array is the best thing you can use. But changing the parameters changes the signatures.
you are kinda implementing polymorphism but in a wrong way..

Categories