What is the difference between these two code excerpts, respectively, in PHP?:
function eat_apple($apple)
{
return true;
}
And:
function eat_apple()
{
$apple = func_get_arg(0);
return true;
}
Or is there a difference? If there is not, what is the point of func_get_arg()? Surely it serves some purpose I'm not aware of?
func_get_arg (and func_get_args) make it possible to have functions with a variable number of parameters, so called variadic functions.
Take array_merge as an example, which takes a variable number of arrays to be merged.
Hello. What is the difference between these two code excerpts, respectively, in PHP?:
-function eat_apple($apple)
+function eat_apple()
{
+ $apple = func_get_arg(0);
return true;
}
what is the point of func_get_arg()? Surely it serves some purpose I'm not aware of?
The officially stated purpose is to:
Return an item from the argument list
-- http://php.net/func-get-arg
In truth, there isn't much difference, and a standard passed argument is usually preferable over func_get_arg().
There are two occasions when you might want to use func_get_arg() rather than using defined arguments:
If you want to have an unlimited number of arguments. Typically, this would be better done with a single array argument, but there are times when you may want to allow unlimited arguments. A real example of a function that works this way is PHP's built-in printf function.
Where you have a complex function where the number of arguments given may alter what the arguments are used for and/or their data type. For example, passing a single argument may cause the function to expect a string, whereas passing two arguments, it may expect an integer first, and then the string. I can't think of any examples of this off the top of my head, but I'm fairly sure there are some. Ordinarily, I would say that this sort of behaviour is bad practice, but I can see how it may be useful for adding features while maintaining backward compatibility.
There are two things that you will definitely lose if you use fung_get_arg() instead of standard function arguments:
The ability to pass by reference.
The ability for your IDE to do any type hinting or auto-completion.
The other possible reason I could think of is avoiding a fatal error.
You have a function:
<?php
function display ($a, $b, $c) {
echo $a . " is " . $b . " " . $c;
}
?>
and you could call
<?php
display ("Rock", "good", "boy");
- this will not throw any error.
display ("Rock", "good");
- this will throw fatal error.
?>
So, now think of the second call, you could avoid the fatal error, see how many arguments are passed with func_get_args and process your code with func_get_arg(1) etc.
Several reasons:
You can use that magic to emulate overloading
You can write function (like printf) which can take undetermined number of arguments.
Example for first:
class a{
function X(MyOBJ $obj){...}
}
class b extends a{
function X(string $s,int $i){...}
}
class c extends b{
function X(){...}
}
This will throw a warning. If you use func_get_args() inside the function to get relevant parameters, no warning will be thrown.
Example for the second:
//not good, you can only send 3 strings
function merge_strings($s1, $s2, $s3){
return $s1 . $s2 . $s3;
}
//good one
function merge_strings(){
return join('',func_get_args());
}
Related
So, now we got new PHP7 and we can check if return type is what we want.
For example,
function foo(): bool
{
$num = 8;
if (10 === $num) {
return true;
} else {
return false;
}
}
foo();
OUTPUT: false
Okey, that was easy? It works like it should, but if return is not what we expect?
function bar(): bool
{
$num = 10;
if (10 === $num) {
return array(['apple', 'banana', 'strawberry']);
} else {
return false;
}
}
bar();
OUTPUT: Uncaught TypeError: Return value of foo() must be of the type boolean, array returned
That was very basic and those examples just show how it works.
If we have function like in code example 2, can we check for multiple return types? Like
function bar(): bool || array <---
{
$num = 10;
if (10 === $num) {
return array(['apple', 'banana', 'strawberry']);
} else {
return false;
}
}
bar();
But however this results: FATAL ERROR syntax error, unexpected '||' (T_BOOLEAN_OR), expecting '{' on line number 2
So is it possible to define multiple return types?
#scott-c-wilson has explained the mechanics of the language rule well.
From a design perspective, having a function that potentially returns different types of result indicates a potential design flaw:
If you're returning your result, or otherwise false if something didn't go to plan; you should probably be throwing an exception instead. If the function processing didn't go according to plan; that's an exceptional situation: leverage the fact. I know PHP itself has a habit of returning false if things didn't work, but that's just indicative of poor design - for the same reason - in PHP.
If your function returns potentially different things, then it's quite possible it's doing more than one thing, which is bad design in your function. Functions should do one thing. If your function has an if/else with the true/false block handling different chunks of processing (as opposed to just handling exit situations), then this probably indicates you ought to have two functions, not one. Leave it to the calling code to decide which is the one to use.
If your function returns two different object types which then can be used in a similar fashion in the calling code (ie: there's no if this: do that; else do this other thing in the calling code), this could indicate you ought to be returning an interface, not a concrete implementation.
there will possibly be legit situations where returning different types is actually the best thing to do. If so: all good. But that's where the benefit of using a loosely typed language comes in: just don't specify the return type of the function. But... that said... the situation probably isn't legit, so work through the preceding design considerations first to determine if you really do have one of these real edge cases where returning different types is warranted.
Is it possible to define multiple return types?
No. That's the point! Multiple return types are confusing and mean you need to do extra non-intuitive checking (I'm looking at you, "===").
From the manual:
"...return type declarations specify the type of the value that will be returned from a function." (emphasis mine)
The type, not the types.
Updating this as of 2020.
There has been vote for Union types and it was accepted to PHP 8.
https://wiki.php.net/rfc/union_types_v2
To have multiple return types in PHP you just need to have PHP 8, otherwise it is simply not possible at all. However, you should not be dumm and set everything as possible return, as it might make your code a mess. #Adam Cameron explains this very well in his answer.
Union types should exist, but they don't.
You can use ?int for example, but then it will expect NULL or INT.
The Answer:
It's not possible. There isn't any way natively through PHP.
However, you can omit the 'Type Declaration' which is ONLY there for strict typing. Just use DocBlocks #return bool|string for example. The IDE will recognize it, but PHP won't care.
http://docs.phpdoc.org/references/phpdoc/tags/return.html
This question already has answers here:
PHP call_user_func vs. just calling function
(8 answers)
Closed 6 months ago.
I dont understand the function, call_user_func() in the sense that i get how it works but I'm not sure why its required or in what context to use it in php. As far as I'm concerned why not just call the function instead of calling a function with a function? Thnx!
call_user_func gives PHP the ability to treat methods and functions as quasi first-class citizens. In functional languages like javascript there is no need for these special tools per-se because a function is an object that happens to be callable.
PHP is getting closer to having this sort of notion though, especially with the closure support that came along with PHP5.3. Take a look at the comment I put under #deceze's answer. There are some other tools (namely variable functions, reflection and now closures) that offer the same basic functionality.
The most notable thing about call_user_func though is how it allows you to treat global functions, static classes and objects with a uniform interface. It's probably the closest thing they have to a single interface to invoke functions no matter how they're implemented. Internally the PHP core group of developers is working to homogenize some sort of a 'callable' or 'invokable' interface for the language, I'm sure we'll see a clean offering in PHP5.4 or the next major release.
I've had a couple situations where this was very necessary. For example, when I was creating a project that allowed a user to construct parts of a programming language, the system would wrap the "tag" definition in a function before running it for security reasons. However, in doing this, I can't simply call those functions, because I don't know when I need to call them, or even what the names would be. Enter call_user_func()...
So, I'm sure you're confused right now. Let me explain. What my system did, was take some XML, and convert it into PHP/HTML/JS with PHP. This allowed for rapid creation of GUIs (which was the goal). Take this XML for example:
<window id="login-win" title="Access Restricted" width="310" height="186" layout="accordion" layoutConfig="animate:true">
<panel id="login-panel" title="User Login">
<form id="login-form" title="Credentials">
<textbox id="login-uname" label="Username"/>
<password id="login-pass" label="Password"/>
<submit text="Login"/>
</form>
</panel>
<panel id="login-register" title="Register">
Nothing, you can't register!
</panel>
</window>
Each XML tag would be read, then fed into it's corresponding PHP function. That function would determine what to do for that 1 tag. In order to pull this off, I had files each named after the tag it handled. So, for example, the tag's file was "submit.php". This file's contents would get wrapped in a generated function, something like:
function tag_submit($variables, $parent, $children){
// deal with the data, then echo what is needed
}
This function's name would be stored in an array, with it's associated tag name, with the rest of the generated functions. This makes it so the function is generated once, and only created when needed, saving memory, since I would do a if(func_exists()) call to determine if I needed it or not.
However, since this is all dynamic, and the user may want to add in a new tag, for say, a < date > tag, I needed to use call_user_func() to get things to work. I can't hard-code a function call if I don't know what the name is.
Hope that all made sense. Basically, yes, it is a rarely used function, but it is still very very useful.
Named functions, anonymous functions, static methods, instance methods and objects with an "__invoke" method are collectively known as 'callables'. If I have a callable it should be possible to call it by placing parentheses afterwards "()" (I'll assume it takes no arguments). This works when our callable is stored in a variable, for example:
$f(); // Call $f
However, what if I store a callable in an object property?
$obj = new stdClass;
$obj->my_func = function() {};
$obj->my_func(); // Error: stdClass does not have a "my_func" method
The problem is that PHP's parser is getting confused because the code is ambiguous, it could mean calling a callable property or calling a method. PHP chooses to always treat this kind of code as a method call, so we cannot call callable properties this way. This is why we need 'call_user_func':
call_user_func($obj->my_func); // Calls $obj->my_func
There are other times when PHP doesn't understand the normal parentheses syntax; for example, PHP currently (5.5) doesn't know how to call the return value of another callable:
get_a_callable()(); // Parse error, unexpected "("
call_user_func(get_a_callable()); // Calls the return value of get_a_callable
It's also not currently possible to call a function definion directly, which is useful to work around PHP's lack of "let" statements, for example:
function($x) { echo $x . $x; }('hello'); // Parse error, unexpected "("
call_user_func(function($x) { echo $x . $x; }, 'hello'); // Calls the function
There are also times where it's useful to have function calls /reified/ as the 'call_user_func' function. For example, when using higher-order functions like array_map:
$funcs = [function() { return 'hello'; },
function() { return 'world'; }];
array_map('call_user_func', $funcs); // ['hello', 'world']
It's also useful when we don't know how many parameters will be needed, ie. we can't substitute our own "function($f, $x, $y, ...) { return $f($x, $y, ...); }".
One particularly nice definition is partial application, which only takes a few lines thanks to call_user_func and call_user_func_array:
function partial() {
$args1 = func_get_args(); // $f, $a, $b, $c, ...
return function() use ($args1) {
// Returns $f($a, $b, $c, ..., $d, $e, $f, ...)
$args2 = func_get_args(); // $d, $e, $f, ...
return call_user_func_array('call_user_func',
array_merge($args1, $args2));
};
}
Setting variable values inside a function call - I don't see this a lot, is this considered good practice?
function myUpdate($status){
...
}
myUpdate($status = 'live');
I personally like it because it's more descriptive. I see it more frequently the other way around, ie., assigning a default value in the function definition.
That's a very bad idea, because it's basically code obfuscation. php does not support keyword arguments, and that can lead to weird stuff. Case in point:
function f($a, $b){
echo 'a: ' . $a . "\n";
echo 'b: ' . $b . "\n";
}
f($b='b-value', $a='a-value');
This program does not only output
a: b-value
b: a-value
but also defines the variables $b and $a in the global context. This is because
f($b='b-value', $a='a-value');
// is the same thing as ...
$b = 'b-value';
$a = 'a-value';
f($b, $a);
There are a few good practices one can do to make remembering method arguments easier:
Configure your editor/IDE to show the signature of functions on highlight.
If a function has lots of arguments that describe some kind of state, consider moving it into an *objec*t (that holds the state instead)
If your function just needs lots of arguments, make it take an array for all non-essential ones. This also allows the method caller not to worry at all about the multitude of options, she just needs to know the ones she's interested in.
All kidding aside, seriously why do you use it? You have to realize it's something totally different than assigning a default value. What you're doing here is assigning the value to a variable, and then passing that variable to the function. The result is, that after the function call, the $status varialbe is still defined.
myUpdate( $status = 'live' );
echo $status; // "live"
Even if this is what you want, I'd say it's less descriptive than just splitting it out in two lines.
No, it's not because it's extra code. Try:
myUpdate('live' /*status*/, 42 /*maxTries*/);
Or if you really wanted named parameters, you could use a map:
myUpdate(array(
'status' => 'live'
));
Normally it would kill type safety, but PHP doesn't have any, anyway.
Well, default value is different thing.
// if you call myUpdate without argument, it will have $status with value live
function myUpdate($status = 'live'){
}
Calling this:
myUpdate($status = 'live');
is equivalent to:
myUpdate('live');
with the only difference being that after the call, if you call it like myUpdate($status = 'live'); you will keep the $status var with value live in the scope where you called the function, not inside it.
But IMHO its much more readable to do it like this:
$status = 'live';
myUpdate($status);
I have been blissfully unaware of the php function func_get_args(), and now that I have discovered it I want to use it everywhere. Are there any limitations of using func_get_args as compared to explicit argument declaration in the function definition?
You shouldn't use func_get_args unless you actually need it.
If you define a function to take a specific number of arguments, PHP will raise an error if you don't supply enough arguments at call time.
If you take any number of arguments via func_get_args, it's up to you to specifically check that all the arguments you're expecting have been passed to your function.
Similarly, you lose the ability to use type hinting, you can't supply default values, and it becomes much harder to tell what arguments your function expects at a glance.
In short, you prevent PHP from helping you catch (potentially difficult to debug) logic errors.
function do_stuff(MyClass tmpValue, array $values, $optional = null) {
// This is vastly better...
}
function do_stuff() {
// ... than this
}
Even if you want to allow a variable number of arguments, you should explicitly specify as many arguments as you can:
/**
* Add some numbers
* Takes two or more numbers to add together
*/
function add_numbers($num_1, $num_2 /* ..., $num_N */) {
$total = 0;
for ($i = 0; $i < func_num_args(); ++$i)
$total += func_get_arg($i);
return $total;
}
add_numbers(1,2); // OK!
add_numbers(1,2,3); // OK!
add_numbers(1) // Error!
For starters I think it has a performance impact.
It makes your code much harder to read and understand.
No automatic error alert will make debugging a pain.
I think auto-completion is harder if not impossible to do for the IDE (it might use the phpdoc #param declaration though)
EDIT: you may use it when your have only one argument : a one-dimensional array, which keys do not matter. It then becomes very handy.
The only limitation I'm aware of is that stuff is harder to check at parse time. Note that this includes parsers for, say, automated documentation tools, since the functions have args that aren't right there in the function declaration
This works without warning:
function test($a)
{
echo 1;
}
test(2, 1);
This will cause warning:
function test($a)
{
echo 1;
}
test();
If it's standard, any reason for this?
Because in the first example test() may use func_get_args() to access its arguments, so it shouldn't throw an error.
In the second example, the $a is not optional. If you want it to be optional, tack a default in the arguments signature like so
function test($a = 1)
{
echo 1;
}
test();
So yes, it is default behaviour, and it makes sense once you know the above.
Concerning Edit
In the edited first example, you will be able to access 2 as $a, however the 1 will only be accessible via func_get_args() (or one of its similar functions like func_get_arg()).
That is the correct behavior. Your function declaration states that it is expecting one argument. If you want to make a function argument optional, you should apply a default value. Otherwise you will raise an exception. Read the PHP documentation on Function Arguments for full details on how to declare your functions and the ways you can pass in values.
[Edit] This should work fine for you:
function test($a = null)
{
echo 1;
}
test();
I'm just speculating, but a function not receiving a parameter it's expecting is potentially more dangerous than a function receiving an extra parameter it can safely ignore.
Also, I wonder if it might have something to do with the fact that PHP will let you declare defaults for the parameter values, so the warning may be to prevent a situation where you've just forgotten to give $a a default