In php you can usually call a function with more parameters than have been defined, e.g.
function f($a, $b) {
return $a . $b;
}
f('a', 'b', 'c', 'e');
is totally valid.
I understand that you can define functions with a variable number of parameters. But in most cases that is not what you want to do.
So in these cases if you mistakenly replace a . by a , you will not even get warning.
$x = '0';
f('a' , 'b' . $x . 'c') // returns ab0c
f('a' , 'b' , $x . 'c') // returns ab
Now in PHP 7 there is the function f($a, $b, ...$others) syntax. So in princable it is possible to discern variable parameter functions from ordinary ones.
Is there a way to get a notice when a function is called with too many parameters?
There is a method of actually counting the variables sent to your function, however you can only do this INSIDE the function or BEFORE the function by counting the sent items.
See http://php.net/manual/en/function.func-num-args.php for more information.
You can also use http://php.net/manual/en/function.func-get-args.php to GET the current arguments sent to the function.
Your issue would however need something like this:
function(){
$count = func_num_args();
if($count > 3){
//too many args
}
else{
//continue your actual code
}
}
Related
First, let me start by saying i'm a real beginner learning mostly PHP. Understanding the patterns and semantics of programming is more important to me than just learning the syntax. I did some research for what I'm going to ask, but I couldn't find any info about it. So, I was thinking... What if I need to do the following... Give a function multiple outputs to pass in other parts of the code. What is the name of this type of functionality (if it exists)? Or If it doesn't exist, why not? And what is the best practice to achieve the same semantic?
More details:
Let's say I want to call a function with one argument and return not only the value back to that same argument call location, but also in another location or into some other part of the program. Meaning a function with two outputs in two different locations, but the second location wouldn't be a call, just an output from the call made in the first location, returned at the same time with the same value output as the first. So, not calling it twice separately... But rather calling once and outputting twice in different locations. The second output would be used to pass the result into another part of the program and therefore wouldn't be appropriate as a "call/input", but more as an "output" only from the "input" value. How can I achieve multiple outputs in functions?
If this seems like a stupid question, I'm sorry. I couldn't find the info anywhere. Thanks in advance
What you want to do is basically this (i'll make it a 'practical' example):
function add($number1, $number2)
{
$result = $number1 + $number2;
return array('number1' => $number1,'number2' => $number2,'result' => $result);
}
$add = add(5,6); // Returns array('number1' => 5, 'number2' => 6, 'result' => 11);
You now have the two arguments and the result of that function at your disposal to use in other functions.
some_function1($add['result']);
...
some_function2($add['number1']);
If the question is about returning more than one variables, it is simply:
function wtf($foobar = true) {
$var1 = "first";
$var2 = "second";
if($foobar === true) {
return $var2;
}
return $var1;
}
You can either have the function return an array of values:
function foo($bar) {
$bat = 1;
return [$bar, $bat];
}
Or you can pass an argument that tells it which value to return:
function foo($bar, $return_bar=false) {
$bat = 1;
return $return_bar ? $bar : $bat;
}
I'm trying to write a function that will take any number of arguments, and will return the first argument, in order, that is valid (in my case !empty).
I've been able to pretty much get it working how I want, except I'm getting some notices because of undefined variables. See below for examples:
function cascade()
{
if (func_num_args() < 1) return false;
foreach (func_get_args() as &$arg) {
if (!empty($arg)) return $arg;
}
return false;
}
You can see that I've tried to declare that each $arg of the foreach is passed by reference, but that doesn't seem to have done the trick.
To elaborate on how I plan to use this function, see below:
$a = 'a';
$c = 'c';
echo cascade($z, $b, $a, $c);
Since $z and $b are undefined, the first non-empty variable in the list is $a so the output is a as expected. However, you then get the undefined variable notices, which I wish to get rid of.
I realise I can just say echo #cascade($z, $b, $a, $c); which would suppress the errors, but I want to know if there is a way around this issue, so that the reference can be passed somehow. Any thoughts?
Edit:
To further highlight what I'm trying to acheive, see the following function that DOES work without throwing errors, even when passed an undefined variable:
// returns default value if input variable is not set
function ifset(&$var, $default = false) {
return isset($var) ? $var : $default;
}
With this function, if param 1 is not set, then the default value in param 2 is returned. Either way, no error is thrown.
What I am trying to achieve is the same result, but with ANY number of arguments, as this function is limited to 1, unless I nest them (gets messy).
A real life example:
This is WHY I want this function and how I would use it in a real life scenario:
<input type="text" name="customerName" value="<?= cascade($order->fullName, $currentUser->fullName, 'Anonymous') ?>">
So if we have an order in the making, and there is a name available from that, we use that, if that info hasn't been saved yet, we use the logged in user's name as the default value, if no one is logged in, we use 'Anonymous'.
Not exactly what I would do in real life, but perhaps it highlights example usage?
For those who are suggesting defining the variables to mitigate the errors, the who point of this function is to work though a chain of values, giving priority to the ones that come first, then moving to the next if that is 'empty' and so on, until eventually a FALSE default value is returned if all are empty.
The Notice you're seeing is triggered at the function call, not inside the function itself. Therefore, there is nothing you can do inside the function to solve the problem. However, there are a number of ways of solving this problem depending on how your variables are prepared before the function call.
Solution #1: Define the variables before the function call.
for instance:
$z = ''; OR $z = null;
or any falsy value like : null, "", 0, "0", 0.0, [], ..., your function will still work as expected and you won't see the notice.
Solution #2: Test for validity before the function call.
if( !isset($z) ){ $z = ''; }
echo cascade($z);
Solution #3: Test for validity as part of the function call.
This is the same thing as solution #2 but a bit more elegant. Use the Ternary function to pass the variable value or an empty string depending on whether or not the variable is set.
echo cascade(
isset($z)?$z:'',
isset($b)?$b:'',
isset($a)?$a:'',
isset($c)?$c:''
);
Solution #4: If using PHP 7 or above, you can use the new Null Coalescing Operator. This is the same thing as solution #3, but more elegant still.
echo cascade($z ?? '', $b ?? '', $a ?? '', $c ?? '');
If you want a clean alternative to your function, you can try this:
function cascade()
{
$args = func_get_args();
while (!($arg = array_shift($args)));
return $arg ? $arg : false;
}
BIG THANKYOU to JBH for Editing significantly this answer.
The undefined variable notice is not from the code in function but it is from the function call cascade($z, $b, $a, $c)
You are passing undefined variables ($z and $b) as arguments to the function. Since they are not defined any where in the code, you are getting notice.
To get rid of the the notices, define the variables before passing them as arguments.
$a = 'a';
$c = 'c';
$z = '';
$b = '';
echo cascade($z, $b, $a, $c);
OR
echo cascade('', '', $a, $c);
Don't know if this is "good enough".
Create an array of the variables and use array filter to remove the null values.
Use array values to reset the keys.
Now $arr[0] is the first non empty item.
https://3v4l.org/PlmrS
$a = 'a';
$c = 'c';
$arr =array_values(array_filter([$z, $b, $a, $c]));
Var_dump($arr);
Thank you for all your kind answers, but unfortunately none of them solved my problem. Perhaps I didn't explain it well enough, or I over-complicated it with too much information confusing the issue, but anyway I've been able to find the answer.
The following function does exactly what I wanted. It uses the variadic syntax (php 5.6 and over) which allows a variable number of arguments, all of which are passed by reference.
function cascade(&...$args)
{
if (count($args) < 1) return false;
foreach ($args as &$arg) {
if (!empty($arg)) return $arg;
}
return false;
}
I know you can use func_num_args to get the number of actual arguments passed in. Is there any way to get the number of formal parameters?
Example:
<?php
function optional($a, $b = null) {
echo func_num_args();
}
optional(1); // 1
optional(1, 1); // 2
optional(1, 1, 1); // 3
I want a way to get 2 in each of those calls to optional, without hard-coding it.
One way is with ReflectionFunction, e.g.:
function optional($a, $b = null) {
return (new ReflectionFunction(__FUNCTION__))->getNumberOfParameters();
}
I have seen in my journey to creaitng and building some of my php applications, the & symbol within front of vars, = and class names.
I understand that these are PHP References, but the docs i have seen and looked at seem to just not explain it in a way that i understand or confusing. How can you explain the following examples that i have seen to make them more understandable.
public static function &function_name(){...}
$varname =& functioncall();
function ($var, &$var2, $var3){...}
Much appreciated
Let's say you have two functions
$a = 5;
function withReference(&$a) {
$a++;
}
function withoutReference($a) {
$a++;
}
withoutReference($a);
// $a is still 5, since your function had a local copy of $a
var_dump($a);
withReference($a);
// $a is now 6, you changed $a outside of function scope
var_dump($a);
So, passing argument by reference allows function to modify it outside of the function scope.
Now second example.
You have a function which returns a reference
class References {
public $a = 5;
public function &getA() {
return $this->a;
}
}
$references = new References;
// let's do regular assignment
$a = $references->getA();
$a++;
// you get 5, $a++ had no effect on $a from the class
var_dump($references->getA());
// now let's do reference assignment
$a = &$references->getA();
$a++;
// $a is the same as $reference->a, so now you will get 6
var_dump($references->getA());
// a little bit different
$references->a++;
// since $a is the same as $reference->a, you will get 7
var_dump($a);
Reference functions
$name = 'alfa';
$address = 'street';
//declaring the function with the $ tells PHP that the function will
//return the reference to the value, and not the value itself
function &function_name($what){
//we need to access some previous declared variables
GLOBAL $name,$address;//or at function declaration (use) keyword
if ($what == 'name')
return $name;
else
return $address;
}
//now we "link" the $search variable and the $name one with the same value
$search =& function_name('name');
//we can use the result as value, not as reference too
$other_search = function_name('name');
//any change on this reference will affect the "$name" too
$search = 'new_name';
var_dump($search,$name,$other_search);
//will output string 'new_name' (length=8)string 'new_name' (length=8)string 'alfa' (length=4)
Usually you use the method with Objects that implemented the same interface, and you want to choose the object you want to work with next.
Passing by reference:
function ($var, &$var2, $var3){...}
I'm sure you saw the examples, so I'll just explain how and when to use it.
The basic scenario is when do you have a big logic that you want to apply to a current object/data, and you do not wish to make more copies of it (in memory).
Hope this helps.
I have a question regarding PHP. Is there any way I could make a function, which has a dynamic number of function inputs?
For example, let's call that function dynamic_func()
It should work in both of these cases, and also in other cases, not depending on number of functions input:
dynamic_func(1,2,3,4)
dynamic_func(1,2,3,4,5,6)
Thanks in advance!
It works as normal.
function dynamic_func()
{
$args=func_get_args(); //get all the arguments as an array
}
dynamic_func(1,2,3,4); //will work
dynamic_func(1,2,3,4,5,6); //will work
I believe PHP will never complain if you pass more arguments than those expected by a function. E.g.:
<?php
function foo($a) {
}
foo(); // invalid (Warning: Missing argument 1 for ...)
foo('a'); // valid
foo('a', 'b'); // surprise... valid!
So you can use func_get_args() and func_num_args() inside foo() to detect how many parameters were actually passed on to that function:
<?php
function foo(/*$a*/) {
echo func_num_args();
var_dump(func_get_args());
}
foo('a', 'b');
Rest is up to you.
there are two possibilitys to do this: using func_get_args like Shakti Singh explained or predefine the arguments like this
function myfunc($arg1 = 1, $arg2 = 2, $arg3 = 3){
echo $arg1.' '.$arg1.' '.$arg3;
}
myfunc(); // outputs "1 2 3";
myfunc(9,8); // outputs "9 8 3";
note that you can set the arguments to any default value that is used if the argument isn't given, but you'll have to define all arguments with this - it isn't as dynamic as using func_get_args.