I want to know how to pass more arguments to my array_walk..
$addresses = array('www.google.com', 'www.yahoo.com', 'www.microsoft.com');
$a = 'hey';
$b = 'hey';
array_walk($addresses, array($this, '_handle'), $a, $b); // $a and $b parameters doesn't get passed
private function _handle($address,$a, $b) {
echo $address; // www.google.com
echo $a // 012
echo $b // 012
}
How do I pass parameters anyway? I have to pass more than 5 parameters.. please teach me.. thanks!
The third parameter is a mixed data type. If you have many parameters, I would suggest putting them into an Array - perhaps an associative array to name them. You'd then pull them back out of that param:
$addresses = array('www.google.com', 'www.yahoo.com', 'www.microsoft.com');
$params = array('first','second');
array_walk($addresses, array($this, '_handle'), $params);
private function _handle($address,$count, $params) {
echo $address; // www.google.com
echo $params[0]; // first
echo $params[1]; // second
}
It will only allow one argument for user data. I suggest passing your values as an array.
array_walk($addresses, array($this, '_handle'), array($a, $b));
The function passed to array_walk() takes 2-3 parameters.
Array Value (as a reference, if needed)
Array Key
Custom data (optional)
To pass multiple variables to array_walk pass an array.
array_walk($addresses, array($this, '_handle'), array('a'=>$a, 'b'=>$b));
private function _handle($address, $k, $data){
echo $address;
echo $data['a'];
echo $data['b'];
}
You can use the use keyword with an anonymous function like this:
Note: $custom_var is a mixed datatype so can be an array if you want to pass several values
$custom_var = 'something';
array_walk(
$array,
function( &$value, $key) use ( $custom_var ){
// Your code here, you can access the value of $custom_var
});
Related
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.
Ok so I have a function with 2 mandatory arguments and then it must have many optional arguments too.
function example($a,$b, $username, $email) {
// code
}
My data for the optional arguments comes from an array
$x = array('joeblogs', 'joe#blogs.com');
How would i be able to parse these? bearing in mind that the function may be required to parse a different set of arguments each time.
An example is with CakePHP you can specify the action arguments that are required
Something like this?
$a = 'a';
$b = 'b';
$x = array('joeblogs', 'joe#blogs.com');
$args = array_merge(array($a, $b), $x);
call_user_func_array('example', $args);
See http://php.net/manual/en/function.call-user-func-array.php
There are two approaches to optional arguments.
In the first, you specify all of the arguments like this:
function example($a, $b, $c=null, $d=null, $e=null)
Parameters $a and $b are required. The others are optional and are null if nothing is provided. This method requires that each of the optional parameters be specified in the indicated order. If you want to call the method using only $a, $b and $e you have to provide null values for $c and $d:
example($a, $b, null, null, $d);
The second method accepts an array as the third parameter. This array will be checked for keys and processed based on the keys found:
function example($a, $b, $c=array()) {
$optionalParam1 = ( !empty( $c['param1'] ) ) : $c['param1'] ? null;
$optionalParam2 = ( !empty( $c['param2'] ) ) : $c['param2'] ? null;
In this way, you can check for each key that may be provided. Null values will be provided for any key not populated.
Following shows syntax for optional parameters and default values
function example($a,$b, $username = '', $email = '') {
}
Another possibility is to pass an "optional values array"
function example($a,$b, $optional_values = array()) {
if($optional_values[0] != '') { blah blah .... }
}
This solution is a merge of your sugestion and Jez's solution.
call_user_func_array(array($controller, $action), $getVars);
Where $controller is the instance of your controller, $action is the string to the action that you want to call, and $getVars is an array of parameters.
The first parameter of the call_user_func_array function is a callback. It's possible to define a method invocation as callback.
Here is a link to the documentation of PHP's callback: http://www.php.net/manual/pt_BR/language.pseudo-types.php#language.types.callback
To pass the array parameters to a function you can use call_user_func_array:
$args = array( 'foo', 'bar', 'joeblogs', 'joe#blogs.com' );
call_user_func_array( 'example', $args );
Or simple pass any number of parameters:
example( $a, $b, $username, $email );
To retrieve the parameters inside function use func_get_args:
function example() {
$args = func_get_args();
print_r( $args );
// output:
// Array (
// [0] => foo
// [1] => bar
// [2] => joeblogs
// [3] => joe#blogs.com
// )
}
I know that it is possible to call a function with a variable number of parameters with call_user_func_array() found here -> http://php.net/manual/en/function.call-user-func-array.php . What I want to do is nearly identical, but instead of a function, I want to call a PHP class with a variable number of parameters in it's constructor.
It would work something like the below, but I won't know the number of parameters, so I won't know how to instantiate the class.
<?php
//The class name will be pulled dynamically from another source
$myClass = '\Some\Dynamically\Generated\Class';
//The parameters will also be pulled from another source, for simplicity I
//have used two parameters. There could be 0, 1, 2, N, ... parameters
$myParameters = array ('dynamicparam1', 'dynamicparam2');
//The instantiated class needs to be called with 0, 1, 2, N, ... parameters
//not just two parameters.
$myClassInstance = new $myClass($myParameters[0], $myParameters[1]);
You can do the following using ReflectionClass
$myClass = '\Some\Dynamically\Generated\a';
$myParameters = array ('dynamicparam1', 'dynamicparam2');
$reflection = new \ReflectionClass($myClass);
$myClassInstance = $reflection->newInstanceArgs($myParameters);
PHP manual: http://www.php.net/manual/en/reflectionclass.newinstanceargs.php
Edit:
In php 5.6 you can achieve this with Argument unpacking.
$myClass = '\Some\Dynamically\Generated\a';
$myParameters = ['dynamicparam1', 'dynamicparam2'];
$myClassInstance = new $myClass(...$myParameters);
I implement this approach a lot when function args are > 2, rather then end up with an Christmas list of arguments which must be in a specific order, I simply pass in an associative array. By passing in an associative array, I can check for necessary and optional args and handle missing values as needed. Something like:
class MyClass
{
protected $requiredArg1;
protected $optionalArg1;
public function __construct(array $options = array())
{
// Check for a necessary arg
if (!isset($options['requiredArg1'])) {
throw new Exception('Missing requiredArg1');
}
// Now I can just localize
$requiredArg1 = $options['requiredArg1'];
$optionalArg1 = (isset($options['optionalArg1'])) ? $options['optionalArg1'] : null;
// Now that you have localized args, do what you want
$this->requiredArg1 = $requiredArg1;
$this->optionalArg1 = $optionalArg1;
}
}
// Example call
$class = 'MyClass';
$array = array('requiredArg1' => 'Foo!', 'optionalArg1' => 'Bar!');
$instance = new $class($array);
var_dump($instance->getRequiredArg1());
var_dump($instance->getOptionalArg1());
I highly recommend using an associative array, however it is possible to use a 0-index array. You will have to be extremely careful when constructing the array and account for indices that have meaning, otherwise you will pass in an array with offset args and wreck havoc with your function.
You can do that using func_get_args().
class my_class {
function __construct( $first = NULL ) {
$params = func_get_args();
if( is_array( $first ) )
$params = $first;
// the $params array will contain the
// arguments passed to the child function
foreach( $params as $p )
echo "Param: $p\n";
}
}
function my_function() {
$instance = new my_class( func_get_args() );
}
echo "you can still create my_class instances like normal:";
$instance = new my_class( "one", "two", "three" );
echo "\n\n\n";
echo "but also through my_function:";
my_function( "one", "two", "three" );
Basically, you simply pass the result of func_get_args to the constructor of your class, and let it decide whether it is being called with an array of arguments from that function, or whether it is being called normally.
This code outputs
you can still create my_class instances like normal:
Param: one
Param: two
Param: three
but also through my_function:
Param: one
Param: two
Param: three
Hope that helps.
I've found here
Is there a call_user_func() equivalent to create a new class instance?
the example:
function createInstance($className, array $arguments = array())
{
if(class_exists($className)) {
return call_user_func_array(array(
new ReflectionClass($className), 'newInstance'),
$arguments);
}
return false;
}
But can somebody tell me if there is an example for classes with protected constructors?
I have the following functions. WordPress functions, but this is really a PHP question. They sort my $term objects according to the artist_lastname property in each object's metadata.
I want to pass a string into $meta in the first function. This would let me reuse this code as I could apply it to various metadata properties.
But I don't understand how I can pass extra parameters to the usort callback. I tried to make a JS style anonymous function but the PHP version on the server is too old (v. 5.2.17) and threw a syntax error.
Any help - or a shove towards the right corner of the manual - gratefully appreciated. Thanks!
function sort_by_term_meta($terms, $meta)
{
usort($terms,"term_meta_cmp");
}
function term_meta_cmp( $a, $b )
{
$name_a = get_term_meta($a->term_id, 'artist_lastname', true);
$name_b = get_term_meta($b->term_id, 'artist_lastname', true);
return strcmp($name_a, $name_b);
}
PHP Version: 5.2.17
I think this question deserves an update. I know the original question was for PHP version 5.2, but I came here looking for a solution and found one for newer versions of PHP and thought this might be useful for other people as well.
For PHP 5.3 and up, you can use the 'use' keyword to introduce local variables into the local scope of an anonymous function. So the following should work:
function sort_by_term_meta(&$terms, $meta) {
usort($terms, function($a, $b) use ($meta) {
$name_a = get_term_meta($a->term_id, 'artist_lastname', true);
$name_b = get_term_meta($b->term_id, 'artist_lastname', true);
return strcmp($name_a, $name_b);
});
}
Some more general code
If you want to sort an array just once and need an extra argument you can use an anonymous function like this:
usort($arrayToSort, function($a, $b) use ($myExtraArgument) {
//$myExtraArgument is available in this scope
//perform sorting, return -1, 0, 1
return strcmp($a, $b);
});
If you need a reusable function to sort an array which needs an extra argument, you can always wrap the anonymous function, like for the original question:
function mySortFunction(&$arrayToSort, $myExtraArgument1, $myExtraArgument2) {
usort($arrayToSort, function($a, $b) use ($myExtraArgument1, $myExtraArgument2) {
//$myExtraArgument1 and 2 are available in this scope
//perform sorting, return -1, 0, 1
return strcmp($a, $b);
});
}
In PHP, one option for a callback is to pass a two-element array containing an object handle and a method name to call on the object. For example, if $obj was an instance of class MyCallable, and you want to call the method1 method of MyCallable on $obj, then you can pass array($obj, "method1") as a callback.
One solution using this supported callback type is to define a single-use class that essentially acts like a closure type:
function sort_by_term_meta( $terms, $meta )
{
usort($terms, array(new TermMetaCmpClosure($meta), "call"));
}
function term_meta_cmp( $a, $b, $meta )
{
$name_a = get_term_meta($a->term_id, $meta, true);
$name_b = get_term_meta($b->term_id, $meta, true);
return strcmp($name_a, $name_b);
}
class TermMetaCmpClosure
{
private $meta;
function __construct( $meta ) {
$this->meta = $meta;
}
function call( $a, $b ) {
return term_meta_cmp($a, $b, $this->meta);
}
}
Assuming you've access to objects and static (PHP 5 or greater), you can create an object and pass the arguments directly there, like so:
<?php
class SortWithMeta {
private static $meta;
static function sort(&$terms, $meta) {
self::$meta = $meta;
usort($terms, array("SortWithMeta", "cmp_method"));
}
static function cmp_method($a, $b) {
$meta = self::$meta; //access meta data
// do comparison here
}
}
// then call it
SortWithMeta::sort($terms, array('hello'));
Assuming you don't have access to objects/static; you could just do a global:
$meta = array('hello'); //define meta in global
function term_meta_cmp($a, $b) {
global $meta; //access meta data
// do comparison here
}
usort($terms, 'term_meta_cmp');
Warning
This function has been DEPRECATED as of PHP 7.2.0. Relying on this function is highly discouraged.
The docs say that create_function() should work on PHP >= 4.0.1. Does this work?
function term_meta_cmp( $a, $b, $meta ) {
echo "$a, $b, $meta<hr>"; // Debugging output
}
$terms = array("d","c","b","a");
usort($terms, create_function('$a, $b', 'return term_meta_cmp($a, $b, "some-meta");'));
This won't help you at all with usort() but might be helpful nevertheless. You could sort the array using one of the other sorting functions, array_multisort().
The idea is to build an array of the values that you would be sorting on (the return values from get_term_meta()) and multisort that against your main $terms array.
function sort_by_term_meta(&$terms, $meta)
{
$sort_on = array();
foreach ($terms as $term) {
$sort_on[] = get_term_meta($term->term_id, $meta, true);
}
array_multisort($sort_on, SORT_ASC, SORT_STRING, $terms);
}
What is the Simplest Solution to Passing Args to usort()?
I like many of the answers here, but I wanted to have a solution that could be done as simply as possible, but could also be demonstrated! When calling usort, supply extra arguments like this...
usort($sortable, [$arg1, $arg2, ... $argn, compareFunction]);
But make sure to define these arguments before, so, you'll end up with something like...
$arg1 = 'something';
$arg2 = 'something else';
$argn = 'yet another thing';
usort($sortable, [$arg1, $arg2, ... $argn, compareFunction]);
Then $arg1, $arg2, and $argn will be available to the compareFunction().
Demo It Up!
To demonstrate, here is a usort() that only considers the first three letters of elements being compared...
function cmp ($a, $b) {
return strcmp(substr($a, 0, $num), substr($a, 0, $num));
}
$terms = ['123a', '123z', '123b',];
$num = 3;
$thing = 4;
usort($terms, [$num, $thing, cmp]);
print_r($terms);
Full Working Demo Online
So I've got a class that I'd like to have it just set defaults if they're not passed in. For example, I can pass it an array called $options.
function new_score($options)
{
}
Then I'd like to have a different function that I can set a var to a default if a key with that var's name doesn't exist in the $options array;
The function definition could look like this:
function _set(&$key, $options, $default)
{
}
I know there's array_key_exists(), and I guess I'm sort of looking for a way to access the variables name.
For example:
$apple = 'orange';
How can I get the string 'apple', so I can look for that key? I know I could take the function _set() and have it look for $key, $var, $options, and $default, but I'd rather abstract it further.
function method($options)
{
//First, set an array of defaults:
$defaults = array( "something" => "default value",
"something_else" => "another default");
//Second, merge the defaults with the $options received:
$options = array_merge($defaults, $options);
//Now you have an array with the received values or defaults if value not received.
echo($options["something"]);
//If you wish, you can import variables into local scope with "extract()"
//but it's better not to do this...
extract($options);
echo($something);
}
References:
http://ar.php.net/manual/en/function.array-merge.php
http://ar.php.net/manual/en/function.extract.php
there's two ways of doing this:
One at a time with the ternary operator:
$key = isset($array['foo']) ? $array['foo'] : 'default';
Or, as an array as a whole:
$defaults = array('foo' => 'bar', 'other' => 'default value');
$array = $array + $defaults;
How about this:
class Configurable
{
private static $defaults = array (
'propertyOne'=>'defaultOne',
'propertyTwo'=>'defaultTwo'
);
private $options;
public function __construct ($options)
{
$this->options = array_merge (self::$defaults, $options);
}
}
From the documentation for array_merge:
If the input arrays have the same
string keys, then the later value for
that key will overwrite the previous
one.