A simple question:
What is the syntax for creating a function with unlimited* arguments in PHP?
Example (ActionScript 3):
function multiTrace(...arguments):void
{
var i:String;
for each(i in arguments)
trace(i);
}
The goal is to have a function that I can call and list any given amount of stylesheets within, eg:
$avian->insertStyles("overall.css", "home.css");
*Subject to obvious limitations (RAM, etc).
function multiTrace()
{
$args = func_get_args();
while ($arg = array_shift($args)) {
echo $arg;
}
}
see: http://php.net/manual/en/function.func-get-args.php
See
http://nl.php.net/manual/en/function.func-get-args.php
function testfunction() {
$arguments = func_get_args();
var_dump($arguments);
}
testfunction("argument1", "argument2");
Result:
array
0 => string 'argument1' (length=9)
1 => string 'argument2' (length=9)
I think you are after the func_get_args function:
http://php.net/manual/en/function.func-get-args.php
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.
This is my array
$sub = array("English"=>"12","Hindi"=>"12","History"=>"12","Geography"=>"12","Mathematics"=>"12","Physics"=>"12","Chemistry"=>"12","Biology"=>"12");
Want to pass this entire array as the parameter of a function & want to sum up the marks(array values) using the function
function sum_marks($sub){--Function body--
}
I don't know if this is the proper syntax for passing an array to a function, help!!
Is this you are looking for?
$mySum = array_sum($sub);
Yes, it is the appropriate syntax for passing an array as an argument to a function.
However, you might consider adding a type declaration for the $sub argument:
function sum_marks(array $sub)
{
return array_sum($sub);
}
Type declarations allow functions to require that parameters are of a certain type at call time. If the given value is of the incorrect type, then an error is generated: in PHP 5, this will be a recoverable fatal error, while PHP 7 will throw a TypeError exception.
However, you really probably just want to use array_sum() directly.
For reference, see:
http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration
http://php.net/manual/en/function.array-sum.php
Try this. It will create a function that has a reference to your array. When you change the array you can call the product of the function, and it will recalculate the sum.
$array = ['English' => '12', 'Swedish' => '12'];
function arraySumCb(&$subject) {
return function () use (&$subject) {
return array_sum($subject);
};
}
$sum = arraySumCb($array);
echo $sum(); // 24
$array['Swedish'] = '15';
echo $sum(); // 27
$array['Swedish'] = '10';
echo $sum(); // 22
Edit: This is how I would do it.
$array = ['English' => '12', 'Swedish' => '12'];
class SumMarks {
private $_subject;
public function __construct(array &$subject = []) {
$this->_subject = &$subject;
}
public function __toString() {
return "" . array_sum($this->_subject);
}
}
$sum = new SumMarks($array);
echo $sum; // 24
$array['Swedish'] = '10';
echo $sum; // 22
Edit: Proper use of PHP anonymous functions
I dont understand your question, please ask with specific question. .
But maybe this what are you want :
function sum_marks($sub){
$result = array_sum($sub);
retrun $result;
}
I have made this little class:
class Analyzer {
public static function analyze($phrases) {
$sortedPhrases = array();
array_walk($phrases, array('self', 'splitByLength'), $sortedPhrases);
var_dump($sortedPhrases);
}
private static function splitByLength($item, $key, &$resArr) {
// line stolen from here: http://stackoverflow.com/a/4786840/603003
// thanks to arnaud576875 <http://stackoverflow.com/users/576875/arnaud576875>
$len = count( preg_split('#\PL+#u', $item, -1, PREG_SPLIT_NO_EMPTY) );
if (!isset($resArr[$len])) {
$resArr[$len] = array();
}
$resArr[$len][] = $item;
var_dump($resArr);
}
}
$phrases = array(
"I can't believe the great content",
"I can't understand the superior information",
"I can't comprehend the amazing data",
"I cannot analyze the amazing data",
"I haven't written to the amazing data"
);
Analyzer::analyze($phrases);
Executing the script results in the output below:
array (size=1)
7 =>
array (size=1)
0 => string 'I can't believe the great content' (length=33)
...
array (size=3)
7 =>
array (size=3)
0 => string 'I can't believe the great content' (length=33)
1 => string 'I can't understand the superior information' (length=43)
2 => string 'I can't comprehend the amazing data' (length=35)
6 =>
array (size=1)
0 => string 'I cannot analyze the amazing data' (length=33)
8 =>
array (size=1)
0 => string 'I haven't written to the amazing data' (length=37)
array (size=0)
empty
All outputs are actually correct except the last one which comes from Analyzer::analyze(). It seems that the variable $sortedPhrases is somehow cleared after array_walk().
Take a better look at array_walk's documentation page.
userdata
If the optional userdata parameter is supplied, it will be passed as
the third parameter to the callback funcname.
That's the third parameter. It's not a reference, it's just a value that gets passed to your callback function.
One (of many) solutions to your problem is to use an object instead (objects are always passed by reference):
class Analyzer {
public static function analyze($phrases) {
$arrObj = new ArrayObject();
array_walk($phrases, array('self', 'splitByLength'), $arrObj);
var_dump($arrObj->getArrayCopy());
}
private static function splitByLength($item, $key, $arrObj) {
// line stolen from here: http://stackoverflow.com/a/4786840/603003
// thanks to arnaud576875 <http://stackoverflow.com/users/576875/arnaud576875>
$len = count( preg_split('#\PL+#u', $item, -1, PREG_SPLIT_NO_EMPTY) );
if (!isset($arrObj[$len])) {
$arrObj[$len] = array();
}
$arrObj[$len][] = $item;
var_dump($arrObj->getArrayCopy());
}
}
(it doesn't have to be an ArrayObject, it can be a stdClass object with an array property, or create your own class if you want...)
Or you can wrap your call within an anonymous function if you really want to work with a reference:
$static = get_called_class();
array_walk($phrases, function($item, $key) use($static, &$sortedPhrases){
$static::splitByLength($item, $key, $sortedPhrases);
});
While the third argument sent to the callback function cannot be a reference itself, it can contain references.
A different approach (to using objects or wrapping your callback in a closure) is to pass an array to the callback, containing a reference to the variable you wish to update. The wrapping array gets passed by-value, but all it contains is the referenced value that you want to change.
class Analyzer {
public static function analyze($phrases) {
// …
array_walk($phrases,
array('self', 'splitByLength'),
array(&$sortedPhrases));
// …
}
private static function splitByLength($item, $key, $extra_args) {
$resArr = &$extra_args[0];
// …
}
}
Pretty sure this is wrong:
array_walk($phrases, array('self', 'splitByLength'), $sortedPhrases);
So, Try this:
$sortedPhrases = array_walk($phrases, 'splitByLength');
And return your values in $sortedPhrases and don't use pass by reference (personal thing)
I can't seem to find anything of this, and was wondering if it's possible to store a function or function reference as a value for an array element. For e.g.
array("someFunc" => &x(), "anotherFunc" => $this->anotherFunc())
Thanks!
You can "reference" any function. A function reference is not a reference in the sense of "address in memory" or something. It's merely the name of the function.
<?php
$functions = array(
'regular' => 'strlen',
'class_function' => array('ClassName', 'functionName'),
'object_method' => array($object, 'methodName'),
'closure' => function($foo) {
return $foo;
},
);
// while this works
$functions['regular']();
// this doesn't
$functions['class_function']();
// to make this work across the board, you'll need either
call_user_func($functions['object_method'], $arg1, $arg2, $arg3);
// or
call_user_func_array($functions['object_method'], array($arg1, $arg2, $arg3));
PHP supports the concept of variable functions, so you can do something like this:
function foo() { echo "bar"; }
$array = array('fun' => 'foo');
$array['fun']();
Yout can check more examples in manual.
Yes, you can:
$array = array(
'func' => function($var) { return $var * 2; },
);
var_dump($array['func'](2));
This does, of course, require PHP anonymous function support, which arrived with PHP version 5.3.0. This is going to leave you with quite unreadable code though.
check out PHP's call_user_func. consider the below example.
consider two functions
function a($param)
{
return $param;
}
function b($param)
{
return $param;
}
$array = array('a' => 'first function param', 'b' => 'second function param');
now if you want to execute all the function in a sequence you can do it with a loop.
foreach($array as $functionName => $param) {
call_user_func($functioName, $param);
}
plus array can hold any data type, be it function call, nested arrays, object, string, integer etc. etc.
I have a function which takes in about 10 arguments, in which most of them are optional. I was wondering if I could implement it in such a way that the user of the function does not need to bother with the order of the parameters.
For example:
public function foo($arg1, $arg2, $arg3='',$arg4='', $arg5='', $arg6='', $arg7=''){}
Now, when I use this function I can simply
$this->foo($arg1val, $arg2val, $arg6val);
Is there a way in php to do so?
Here is how I implemented this:
I've listed the parameters accepted by the function in the API, so the user can pass the parameters in any order in an array with key=>value pairs.
For example:
public function argumentsFilter($origParams, $newParams){
$tmpArr = array();
foreach ($origParams as $origKey){
foreach($newParams as $newKey => $newVal){
if($newKey == $origKey){
$tmpArr[$origKey] = $newVal;
}
}
if(empty($tmpArr[$origKey])){
$tmpArr[$origKey] = '';
}
}
return $tmpArr;
}
public function foo($arg1, $arg2, $arg=array()){
$validArgList = array('arg3', 'arg4', 'arg5', 'arg6', 'arg7');
$correctedArgList = $this->argumentsFilter($validArgList, $arg);
}
Is there a more elegant way to do this?
10 parameters for a function is clearly too much. Pass arrays instead:
function foo(array $params) {
$defaults = array('foo' => true, 'bar' => false, ...);
$params = array_intersect_key($params, $defaults) + $defaults;
// work with $params['foo']
// maybe extract($params)
}
This example shows a function that accepts an arbitrary number of "named parameter" in any order, filters invalid values and establishes defaults values.
It is not possible, since php doesn't support named arguments.
You have 2 choices: to use array or to redesign your function so it has fewer parameters (the latter is preferred).
There are many ways to do that, but I recommend this method:
function doSomething($required, /*optional*/ $arguments = array()) {
$arguments = array_merge(array(
// set defaults
"argument" => "default value",
), $arguments);
var_dump($arguments);
}
It is very clean and easy to understand.