I'm curious to know if there is some way to call a function using an associative array to declare the parameters.
For instance if I have this function:
function test($hello, $world) {
echo $hello . $world;
}
Is there some way to call it doing something like this?
call('test', array('hello' => 'First value', 'world' => 'Second value'));
I'm familiar with using call_user_func and call_user_func_array, but I'm looking for something more generic that I can use to call various methods when I don't know what parameters they are looking for ahead of time.
Edit:
The reason for this is to make a single interface for an API front end. I'm accepting JSON and converting that into an array. So, I'd like different methods to be called and pass the values from the JSON input into the methods.
Since I want to be able to call an assortment of different methods from this interface, I want a way to pass parameters to the functions without knowing what order they need to be in. I'm thinking using reflections will get me the results I'm looking for.
With PHP 5.4+, this works
function test($assocArr){
foreach( $assocArr as $key=>$value ){
echo $key . ' ' . $value . ' ';
}
}
test(['hello'=>'world', 'lorem'=>'ipsum']);
Check the php manual for call_user_func_array
Also, look up token operator (...). It is a way to use varargs with functions in PHP. You can declare something like this: -
function func( ...$params)
{
echo $params[0] . ',' . parama[1];
}
You can use this function internal in your functions func_get_args()
So, you can use it like this one:
function test() {
$arg_list = func_get_args();
echo $arg_list[0].' '.$arg_list[1];
}
test('hello', 'world');
The following should work ...
function test($hello, $world) {
echo $hello . $world;
}
$callback = 'test'; <-- lambdas also work here, BTW
$parameters = array('hello' => 'First value', 'world' => 'Second value');
$reflection = new ReflectionFunction($callback);
$new_parameters = array();
foreach ($reflection->getParameters() as $parameter) {
$new_parameters[] = $parameters[$parameter->name];
}
$parameters = $new_parameters;
call_user_func_array($callback, $parameters);
Related
I need to pass a function as a parameter to another function and then call the passed function from within the function...This is probably easier for me to explain in code..I basically want to do something like this:
function ($functionToBeCalled)
{
call($functionToBeCalled,additional_params);
}
Is there a way to do that.. I am using PHP 4.3.9
Thanks!
I think you are looking for call_user_func.
An example from the PHP Manual:
<?php
function barber($type) {
echo "You wanted a $type haircut, no problem";
}
call_user_func('barber', "mushroom");
call_user_func('barber', "shave");
?>
function foo($function) {
$function(" World");
}
function bar($params) {
echo "Hello".$params;
}
$variable = 'bar';
foo($variable);
Additionally, you can do it this way. See variable functions.
In php this is very simple.
<?php
function here() {
print 'here';
}
function dynamo($name) {
$name();
}
//Will work
dynamo('here');
//Will fail
dynamo('not_here');
I know the original question asked about PHP 4.3, but now it's a few years later and I just wanted to advocate for my preferred way to do this in PHP 5.3 or higher.
PHP 5.3+ now includes support for anonymous functions (closures), so you can use some standard functional programming techniques, as in languages like JavaScript and Ruby (with a few caveats). Rewriting the call_user_func example above in "closure style" would look like this, which I find more elegant:
$barber = function($type) {
echo "You wanted a $type haircut, no problem\n";
};
$barber('mushroom');
$barber('shave');
Obviously, this doesn't buy you much in this example - the power and flexibility comes when you pass these anonymous functions to other functions (as in the original question). So you can do something like:
$barber_cost = function($quantity) {
return $quantity * 15;
};
$candy_shop_cost = function($quantity) {
return $quantity * 4.50; // It's Moonstruck chocolate, ok?
};
function get_cost($cost_fn, $quantity) {
return $cost_fn($quantity);
}
echo '3 haircuts cost $' . get_cost($barber_cost, 3) . "\n";
echo '6 candies cost $' . get_cost($candy_shop_cost, 6) . "\n";
This could be done with call_user_func, of course, but I find this syntax much clearer, especially once namespaces and member variables get involved.
One caveat: I'll be the first to admit I don't know exactly what's going on here, but you can't always call a closure contained in a member or static variable, and possibly in some other cases. But reassigning it to a local variable will allow it to be invoked. So, for example, this will give you an error:
$some_value = \SomeNamespace\SomeClass::$closure($arg1, $arg2);
But this simple workaround fixes the issue:
$the_closure = \SomeNamespace\SomeClass::$closure;
$some_value = $the_closure($arg1, $arg2);
You could also use call_user_func_array(). It allows you to pass an array of parameters as the second parameter so you don't have to know exactly how many variables you're passing.
If you need pass function with parameter as parameter, you can try this:
function foo ($param1){
return $param1;
}
function bar ($foo_function, $foo_param){
echo $foo_function($foo_param);
}
//call function bar
bar('foo', 'Hi there'); //this will print: 'Hi there'
phpfiddle example
Hope it'll be helpful...
If you want to do this inside a PHP Class, take a look at this code:
// Create a sample class
class Sample
{
// Our class displays 2 lists, one for images and one for paragraphs
function __construct( $args ) {
$images = $args['images'];
$items = $args['items'];
?>
<div>
<?php
// Display a list of images
$this->loop( $images, 'image' );
// notice how we pass the name of the function as a string
// Display a list of paragraphs
$this->loop( $items, 'content' );
// notice how we pass the name of the function as a string
?>
</div>
<?php
}
// Reuse the loop
function loop( $items, $type ) {
// if there are items
if ( $items ) {
// iterate through each one
foreach ( $items as $item ) {
// pass the current item to the function
$this->$type( $item );
// becomes $this->image
// becomes $this->content
}
}
}
// Display a single image
function image( $item ) {
?>
<img src="<?php echo $item['url']; ?>">
<?php
}
// Display a single paragraph
function content( $item ) {
?>
<p><?php echo $item; ?></p>
<?php
}
}
// Create 2 sample arrays
$images = array( 'image-1.jpg', 'image-2.jpg', 'image-3.jpg' );
$items = array( 'sample one', 'sample two', 'sample three' );
// Create a sample object to pass my arrays to Sample
$elements = { 'images' => $images, 'items' => $items }
// Create an Instance of Sample and pass the $elements as arguments
new Sample( $elements );
I am writing some PHP code that would generate HTML files from templates.
I would like, if possible, to make a function that would take any strings I feed the function with, and put that into the file. Like so:
function generator($a, $b, $c, $n...){
$filename = $a . ".html";
ob_start ();
echo $b;
echo $c;
echo $d;
echo $n...;
$buffer = ob_get_clean();
file_put_contents($a, $buffer);
}
I need this, because different pages would have different number of include files, and with this I would be able to skip making different functions for specific pages. Just an iterator, and that's it.
Thanks!
From PHP 5.6+ you can use ... to indicate a variable number of arguments:
function test (... $args)
{
foreach ($args as $arg) {
echo $arg;
}
}
test("testing", "variable"); // testing variable
Demo
Variable-length argument lists from the manual
So, your function would look something like this:
function generator($a, $b, $c, ... $n) {
$filename = $a . ".html";
ob_start();
echo $b;
echo $c;
foreach ($n as $var) {
echo $var;
}
$buffer = ob_get_clean();
file_put_contents($a, $buffer);
}
You can also use variadic functions (PHP 5.6+) :
function generator($a, ...$args) {
echo $a . "\n";
print_r($args);
}
generator("test", 1, 2, 3, 4);
Outputs :
"test"
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
You can make it using an array as following :
function generator($array){
// set the first item of the array as name of the .html file and take it out of the array.
$filename = array_shift($array) . ".html";
ob_start ();
// echo all the array fields
foreach($array as $a){
echo $a;
}
$buffer = ob_get_clean();
file_put_contents($a, $buffer);
}
You can pass the array directly to call the function like the following :
generator( ["val_1", "val_2", "val_3"] );
Just use func_get_args(); inside your function to return an array of all arguments passed in.
You can also use func_get_arg($arg_num) to return a specific argument, or func_num_args to return the number of arguments.
All PHP functions allow any number of parameters, they just won't be callable by name, the only way is with these 3 functions.
Note, you may use a variadic argument as the last in the parameter list like so:
function my_func($x,$y, ... $z){
//Now $z is an array of all arguments after the first two
}
In the process of good design, I would think carefully about when and where to use things such as this. For example I currently work on a project that probably has over 200K lines of code and for better of worse this is actually never used.
The most common way is to pass an array "struct" to the method:
$args = array();
$args['kitchen'] = 'sink';
$args['bath'] = 'room';
$args['cat'] = array('fur','tail');
$func->someFunction($args);
If you wanted to have more control over the data you could create a struct and access that within the class. Public functions act as handlers.
class SomeClass {
....
private $args
public function setArgs($arg1,$arg2,$arg3) {
$this->arg1 = $arg1;
...
}
public function getArgs() {
return $this->args;
}
More rarely you can have C++ like control where you use a class just as a struct:
class MyStruct {
public $foo;
public $bar;
private $secret;
private function getSecret() {
return $secret;
}
protect function setSecret($val) {
$secret = $val;
}
}
Already mentioned is '...' which I nearly never see but it's interesting, though how useful ? Does this help explain what is going on?
function someFunction(... $args)
Usually you will see a mix of things in methods which helps articulate the purpose of it.
private function someSmallFunc($list = array(), $val = '', $limit = 10)
This example is to illustrate the natural grouping of information, data is in a list, $val is used for something to control the method along with $limit say limits the number of query results. Hence, you should think in this way about your methods IMO.
Also if you notice default values are set ($limit = 10) to in case they aren't passed in. For example if you call someSmallFunc($data, $someVal) (opposed to say someSmallFunc($data, $someVal, 20) ) and not pass in $limit it will default to 10.
I'm trying to make an associative array with values that are references to functions. What is the proper way to do this? This code works, but gives me a warning.
Code
<?php
$mergeCodes = array(
'rev:(\d+)' => reverse_me,
);
$test = "This is a [[rev:1234]] test";
echo "BEFORE: $test\n";
foreach ($mergeCodes as $code => $callback) {
$code = '\[\[' . $code . '\]\]';
$test = preg_replace_callback( "/$code/", $callback, $test );
}
echo "AFTER: $test\n";
function reverse_me($input) {
return strrev($input[1]);
}
?>
Output
PHP Notice: Use of undefined constant reverse_me - assumed 'reverse_me' in /tmp/test2.php on line 4
BEFORE: This is a [[rev:1234]] test
AFTER: This is a 4321 test
As far as I know, PHP does not have such concept. You're probably confused by JavaScript.
It seems that your final purpose is to make a call to preg_replace_callback(). As the name suggests you have to feed it with a callback and that's something pretty simple. All you need is a regular variable that contains one of these:
A string with a variable name: 'foo'
An array with a class name and a method name: array('Foo', 'doBar')
An array with a class instance and a method name: array($myFoo, 'doBar')
Find further reference at https://www.php.net/manual/en/language.types.callable.php
In PHP 5.3, you can store anonymous functions (closures) in variables:
$reverse_me = function($input) {
return strrev($input[1]);
}
$mergeCodes = array(
'rev:(\d+)' => $reverse_me
);
Or you could even do this:
$mergeCodes = array(
'rev:(\d+)' => function($input) {
return strrev($input[1]);
}
);
See http://php.net/functions.anonymous for more info.
I fixed it by making the value the string 'reverse_me'. I guess $callback being a string was not very intuitive to me.
I have a function variable like this...
$aName = "My Name";
The function need to pass in like this:
$sayHelloFunction = function sayHello($aName){
echo($aName);
}
Than, I have a method that responsible for execute the sayHelloFunction:
runningFunction($sayHelloFunction($aName));
in the runningFunction, it will have some condition to execute the function, but when I pass the "$sayHelloFunction($aName)" to runningFunction, it execute automatically, but I would like to pass the variable $aName as well, how can I achieve it? Thank you.
runningFunction($sayHelloFunction, $aName);
Simples.
You will have to pass the arguments separately. However, you could wrap them in an array so that you can pass them to runningFunction as a single argument, like this:
$printFunction = function($args) {
print $args['lastname'].', '.$args['firstname'];
};
function runningFunction($f, $a) {
$f($a);
}
$firstname = 'Bob';
$lastname = 'Smith';
$functionArguments = array(
'firstname' => $firstname,
'lastname' => $lastname
);
runningFunction($printFunction, $functionArguments);
If you want your dynamic functions to get "proper" arguments, then I see no way around something like this:
function runningFunction($f, $a) {
switch(count($a)) {
0: $f(); break;
1: $f($a[0]); break;
2: $f($a[0], $a[1]); break;
3: $f($a[0], $a[1], $a[2]); break;
// and so on
}
}
Pass the parameters as an array, and then use call_user_func_array() to call your function.
This way your runningFunction() will be absolutely abstract (as you requested), it can call any type of function, it's your responsibility to pass the right number of parameters.
function runningFunction ($callback, $parameters=array()) {
call_user_func_array($callback, $parameters);
}
runningFunction($sayHelloFunction, array($aName));
call_user_func_array()
as xconspirisist suggested pass $aName as a seperate parameter to the function.
Details on Variable Functions can be found on the PHP site.
Use an anonymous function when calling runningFunction
function runningFunction($func) {
$func();
}
runningFunction(function() {
$sayHelloFunction($aName));
// You can do more function calls here...
});
This failed:
define('DEFAULT_ROLES', array('guy', 'development team'));
Apparently, constants can't hold arrays. What is the best way to get around this?
define('DEFAULT_ROLES', 'guy|development team');
//...
$default = explode('|', DEFAULT_ROLES);
This seems like unnecessary effort.
Since PHP 5.6, you can declare an array constant with const:
<?php
const DEFAULT_ROLES = array('guy', 'development team');
The short syntax works too, as you'd expect:
<?php
const DEFAULT_ROLES = ['guy', 'development team'];
If you have PHP 7, you can finally use define(), just as you had first tried:
<?php
define('DEFAULT_ROLES', array('guy', 'development team'));
PHP 5.6+ introduced const arrays - see Andrea Faulds' answer.
You can also serialize your array and then put it into the constant:
# define constant, serialize array
define ("FRUITS", serialize (array ("apple", "cherry", "banana")));
# use it
$my_fruits = unserialize (FRUITS);
You can store them as static variables of a class:
class Constants {
public static $array = array('guy', 'development team');
}
# Warning: array can be changed lateron, so this is not a real constant value:
Constants::$array[] = 'newValue';
If you don't like the idea that the array can be changed by others, a getter might help:
class Constants {
private static $array = array('guy', 'development team');
public static function getArray() {
return self::$array;
}
}
$constantArray = Constants::getArray();
EDIT
Since PHP5.4, it is even possible to access array values without the need for intermediate variables, i.e. the following works:
$x = Constants::getArray()['index'];
If you are using PHP 5.6 or above, use Andrea Faulds answer
I am using it like this. I hope, it will help others.
config.php
class app{
private static $options = array(
'app_id' => 'hello',
);
public static function config($key){
return self::$options[$key];
}
}
In file, where I need constants.
require('config.php');
print_r(app::config('app_id'));
This is what I use. It is similar to the example provided by soulmerge, but this way you can get the full array or just a single value in the array.
class Constants {
private static $array = array(0 => 'apple', 1 => 'orange');
public static function getArray($index = false) {
return $index !== false ? self::$array[$index] : self::$array;
}
}
Use it like this:
Constants::getArray(); // Full array
// OR
Constants::getArray(1); // Value of 1 which is 'orange'
You can store it as a JSON string in a constant. And application point of view, JSON can be useful in other cases.
define ("FRUITS", json_encode(array ("apple", "cherry", "banana")));
$fruits = json_decode (FRUITS);
var_dump($fruits);
PHP 7+
As of PHP 7, you can just use the define() function to define a constant array :
define('ANIMALS', [
'dog',
'cat',
'bird'
]);
echo ANIMALS[1]; // outputs "cat"
I know it's a bit old question, but here is my solution:
<?php
class Constant {
private $data = [];
public function define($constant, $value) {
if (!isset($this->data[$constant])) {
$this->data[$constant] = $value;
} else {
trigger_error("Cannot redefine constant $constant", E_USER_WARNING);
}
}
public function __get($constant) {
if (isset($this->data[$constant])) {
return $this->data[$constant];
} else {
trigger_error("Use of undefined constant $constant - assumed '$constant'", E_USER_NOTICE);
return $constant;
}
}
public function __set($constant,$value) {
$this->define($constant, $value);
}
}
$const = new Constant;
I defined it because I needed to store objects and arrays in constants so I installed also runkit to php so I could make the $const variable superglobal.
You can use it as $const->define("my_constant",array("my","values")); or just $const->my_constant = array("my","values");
To get the value just simply call $const->my_constant;
Yes, You can define an array as constant. From PHP 5.6 onwards, it is possible to define a constant as a scalar expression, and it is also possible to define an array constant. It is possible to define constants as a resource, but it should be avoided, as it can cause unexpected results.
<?php
// Works as of PHP 5.3.0
const CONSTANT = 'Hello World';
echo CONSTANT;
// Works as of PHP 5.6.0
const ANOTHER_CONST = CONSTANT.'; Goodbye World';
echo ANOTHER_CONST;
const ANIMALS = array('dog', 'cat', 'bird');
echo ANIMALS[1]; // outputs "cat"
// Works as of PHP 7
define('ANIMALS', array(
'dog',
'cat',
'bird'
));
echo ANIMALS[1]; // outputs "cat"
?>
With the reference of this link
Have a happy coding.
Can even work with Associative Arrays.. for example in a class.
class Test {
const
CAN = [
"can bark", "can meow", "can fly"
],
ANIMALS = [
self::CAN[0] => "dog",
self::CAN[1] => "cat",
self::CAN[2] => "bird"
];
static function noParameter() {
return self::ANIMALS[self::CAN[0]];
}
static function withParameter($which, $animal) {
return "who {$which}? a {$animal}.";
}
}
echo Test::noParameter() . "s " . Test::CAN[0] . ".<br>";
echo Test::withParameter(
array_keys(Test::ANIMALS)[2], Test::ANIMALS["can fly"]
);
// dogs can bark.
// who can fly? a bird.
if you're using PHP 7 & 7+, you can use fetch like this as well
define('TEAM', ['guy', 'development team']);
echo TEAM[0];
// output from system will be "guy"
Using explode and implode function we can improvise a solution :
$array = array('lastname', 'email', 'phone');
define('DEFAULT_ROLES', implode (',' , $array));
echo explode(',' ,DEFAULT_ROLES ) [1];
This will echo email.
If you want it to optimize it more you can define 2 functions to do the repetitive things for you like this :
//function to define constant
function custom_define ($const , $array) {
define($const, implode (',' , $array));
}
//function to access constant
function return_by_index ($index,$const = DEFAULT_ROLES) {
$explodedResult = explode(',' ,$const ) [$index];
if (isset ($explodedResult))
return explode(',' ,$const ) [$index] ;
}
Hope that helps . Happy coding .
Doing some sort of ser/deser or encode/decode trick seems ugly and requires you to remember what exactly you did when you are trying to use the constant. I think the class private static variable with accessor is a decent solution, but I'll do you one better. Just have a public static getter method that returns the definition of the constant array. This requires a minimum of extra code and the array definition cannot be accidentally modified.
class UserRoles {
public static function getDefaultRoles() {
return array('guy', 'development team');
}
}
initMyRoles( UserRoles::getDefaultRoles() );
If you want to really make it look like a defined constant you could give it an all caps name, but then it would be confusing to remember to add the '()' parentheses after the name.
class UserRoles {
public static function DEFAULT_ROLES() { return array('guy', 'development team'); }
}
//but, then the extra () looks weird...
initMyRoles( UserRoles::DEFAULT_ROLES() );
I suppose you could make the method global to be closer to the define() functionality you were asking for, but you really should scope the constant name anyhow and avoid globals.
You can define like this
define('GENERIC_DOMAIN',json_encode(array(
'gmail.com','gmail.co.in','yahoo.com'
)));
$domains = json_decode(GENERIC_DOMAIN);
var_dump($domains);
Constants can only contain scalar values, I suggest you store the serialization (or JSON encoded representation) of the array.
If you are looking this from 2009, and you don't like AbstractSingletonFactoryGenerators, here are a few other options.
Remember, arrays are "copied" when assigned, or in this case, returned, so you are practically getting the same array every time. (See copy-on-write behaviour of arrays in PHP.)
function FRUITS_ARRAY(){
return array('chicken', 'mushroom', 'dirt');
}
function FRUITS_ARRAY(){
static $array = array('chicken', 'mushroom', 'dirt');
return $array;
}
function WHAT_ANIMAL( $key ){
static $array = (
'Merrick' => 'Elephant',
'Sprague' => 'Skeleton',
'Shaun' => 'Sheep',
);
return $array[ $key ];
}
function ANIMAL( $key = null ){
static $array = (
'Merrick' => 'Elephant',
'Sprague' => 'Skeleton',
'Shaun' => 'Sheep',
);
return $key !== null ? $array[ $key ] : $array;
}