Functions PHP
Functions PHP
Table of Contents
User-defined functions
Function arguments
Returning values
Variable functions
Internal (built-in) functions
Anonymous functions
Arrow Functions
User-defined functions
A function may be defined using syntax such as the following:
<?php
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
{
echo "Example function.\n";
return $retval;
}
?>
Any valid PHP code may appear inside a function, even other functions and class
definitions.
Function names follow the same rules as other labels in PHP. A valid function name starts
with a letter or underscore, followed by any number of letters, numbers, or underscores. As
a regular expression, it would be expressed thus: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$.
Tip
Functions need not be defined before they are referenced, except when a function is
conditionally defined as shown in the two examples below.
When a function is defined in a conditional manner such as the two examples shown. Its
definition must be processed prior to being called.
<?php
$makefoo = true;
bar();
if ($makefoo) {
function foo()
{
echo "I don't exist until program execution reaches me.\n";
}
}
if ($makefoo) foo();
function bar()
{
echo "I exist immediately upon program start.\n";
}
?>
<?php
function foo()
{
function bar()
{
echo "I don't exist until foo() is called.\n";
}
}
foo();
bar();
?>
All functions and classes in PHP have the global scope - they can be called outside a function
even if they were defined inside and vice versa.
PHP does not support function overloading, nor is it possible to undefine or redefine
previously-declared functions.
Note: Function names are case-insensitive for the ASCII characters A to Z, though it is usually
good form to call functions as they appear in their declaration.
Both variable number of arguments and default arguments are supported in functions. See
also the function references for func_num_args(), func_get_arg(), and func_get_args() for more
information.
<?php
function recursion($a)
{
if ($a < 20) {
echo "$a\n";
recursion($a + 1);
}
}
?>
Note: Recursive function/method calls with over 100-200 recursion levels can smash the
stack and cause a termination of the current script. Especially, infinite recursion is
considered a programming error.
Function arguments
Information may be passed to functions via the argument list, which is a comma-delimited
list of expressions. The arguments are evaluated from left to right.
PHP supports passing arguments by value (the default), passing by reference, and default
argument values. Variable-length argument lists are also supported.
<?php
function takes_array($input)
{
echo "$input[0] + $input[1] = ", $input[0]+$input[1];
}
?>
As of PHP 8.0.0, the list of function arguments may include a trailing comma, which will be
ignored. That is particularly useful in cases where the list of arguments is long or contains
long variable names, making it convenient to list arguments vertically.
<?php
function takes_many_args(
$first_arg,
$second_arg,
$a_very_long_argument_name,
$arg_with_default = 5,
$again = 'a default string', // This trailing comma was not permitted before 8.0.0.
)
{
// ...
}
?>
By default, function arguments are passed by value (so that if the value of the argument
within the function is changed, it does not get changed outside of the function). To allow a
function to modify its arguments, they must be passed by reference.
<?php
function add_some_extra(&$string)
{
$string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str; // outputs 'This is a string, and something extra.'
?>
A function may define C++-style default values for scalar arguments as follows:
<?php
function makecoffee($type = "cappuccino")
{
return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");
?>
PHP also allows the use of arrays and the special type NULL as default values, for example:
The default value must be a constant expression, not (for example) a variable, a class
member or a function call.
Note that when using default arguments, any defaults should be on the right side of any
non-default arguments; otherwise, things will not work as expected. Consider the following
code snippet:
<?php
function makeyogurt($type = "acidophilus", $flavour)
{
return "Making a bowl of $type $flavour.\n";
}
<?php
function makeyogurt($flavour, $type = "acidophilus")
{
return "Making a bowl of $type $flavour.\n";
}
Note: Arguments that are passed by reference may have a default value.
Variable-length argument lists
PHP has support for variable-length argument lists in user-defined functions by using the
... token.
Note: It is also possible to achieve variable-length arguments by using func_num_args(), func_get_arg(), and
func_get_args() functions. This technique is not recommended as it was used prior to the introduction of the ...
token.
Argument lists may include the ... token to denote that the function accepts a variable
number of arguments. The arguments will be passed into the given variable as an array; for
example:
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
10
... can also be used when calling functions to unpack an array or Traversable variable or
literal into the argument list:
<?php
function add($a, $b) {
return $a + $b;
}
$a = [1, 2];
echo add(...$a);
?>
3
3
You may specify normal positional arguments before the ... token. In this case, only the
trailing arguments that don't match a positional argument will be added to the array
generated by ....
It is also possible to add a type declaration before the ... token. If this is present, then all
arguments captured by ... must be objects of the hinted class.
<?php
function total_intervals($unit, DateInterval ...$intervals) {
$time = 0;
foreach ($intervals as $interval) {
$time += $interval->$unit;
}
return $time;
}
$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';
3 days
Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval,
null given, called in - on line 14 and defined in - on line 2
Finally, variable arguments can also be passed by reference by prefixing the ... with an
ampersand (&).
No special syntax is required to note that a function is variadic; however access to the
function's arguments must use func_num_args(), func_get_arg() and func_get_args().
The first example above would be implemented as follows in old versions of PHP:
<?php
function sum() {
$acc = 0;
foreach (func_get_args() as $n) {
$acc += $n;
}
return $acc;
}
10
User Contributed Notes
shaman_master at list dot ru 22-Nov-2019 04:38
You can use the class/interface as a type even if the class/interface is not defined yet or the class/interface implements
current class/interface.
<?php
interface RouteInterface
{
public function getGroup(): ?RouteGroupInterface;
}
interface RouteGroupInterface extends RouteInterface
{
public function set(RouteInterface $item);
}
?>
'self' type - alias to current class/interface, it's not changed in implementations. This code looks right but throw error:
<?php
class Route
{
protected $name;
// method must return Route object
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
}
class RouteGroup extends Route
{
// method STILL must return only Route object
public function setName(string $name): self
{
$name .= ' group';
return parent::setName($name);
}
}
?>
There is a possibility to use parent keyword as type hint which is not mentioned in the documentation.
Following code snippet will be executed w/o errors on PHP version 7. In this example, parent keyword is referencing on
ParentClass instead of ClassTrait.
<?php
namespace TestTypeHints;
class ParentClass
{
public function someMethod()
{
echo 'Some method called' . \PHP_EOL;
}
}
trait ClassTrait
{
private $original;
Outputs:
Some method called
Quote:
"The declaration can be made to accept NULL values if the default value of the parameter is set to NULL."
<?php
function foo(?string $bar) {
//...
}
PHP 7+ does type coercion if strict typing is not enabled, but there's a small gotcha: it won't convert null values into
anything.
You must explicitly set your default argument value to be null (as explained in this page) so your function can also
receive nulls.
For instance, if you type an argument as "string", but pass a null variable into it, you might expect to receive an empty
string, but actually, PHP will yell at you a TypeError.
<?php
function null_string_wrong(string $str) {
var_dump($str);
}
function null_string_correct(string $str = null) {
var_dump($str);
}
$null = null;
null_string_wrong('a'); //string(1) "a"
null_string_correct('a'); //string(1) "a"
null_string_correct(); //NULL
null_string_correct($null); //NULL
null_string_wrong($null); //TypeError thrown
?>
<?php
class A {
const FOO = 'default';
function bar( $val = self::FOO ) {
echo $val;
}
}
$a = new A();
$a->bar(); // Will echo "default"
There are fewer restrictions on using ... to supply multiple arguments to a function call than there are on using it to
declare a variadic parameter in the function declaration. In particular, it can be used more than once to unpack
arguments, provided that all such uses come after any positional arguments.
<?php
$array1 = [[1],[2],[3]];
$array2 = [4];
$array3 = [[5],[6],[7]];
The Right Thing for the error case above would be for $result==[1,2,3,4], but this isn't yet (v7.1.8) supported.
<?php
function variadic($first, ...$most, $last)
{/*etc.*/}
variadic(1, 2, 3, 4, 5);
?>
results in a fatal error, even though it looks like the Thing To Do™ would be to set $first to 1, $most to [2, 3, 4], and $last
to 5.
A function's argument that is an object, will have its properties modified by the function although you don't need to pass
it by reference.
<?php
$x = new stdClass();
$x->prop = 1;
f($x);
<?php
$y = [ 'prop' => 1 ];
function g( $a )
{
$a['prop'] ++;
echo $a['prop']; // shows: 2
}
g($y);
I wondered if variable length argument lists and references works together, and what the syntax
might be. It is not mentioned explicitly yet in the php manual as far as I can find. But other sources
mention the following syntax "&...$variable" that works in php 5.6.16.
<?php
function foo(&...$args)
{
$i = 0;
foreach ($args as &$arg) {
$arg = ++$i;
}
}
foo($a, $b, $c);
echo 'a = ', $a, ', b = ', $b, ', c = ', $c;
?>
Gives
a = 1, b = 2, c = 3
#!/usr/bin/php
<?php
function sum($array,$max){ //For Reference, use: "&$array"
$sum=0;
for ($i=0; $i<2; $i++){
#$array[$i]++; //Uncomment this line to modify the array within the function.
$sum += $array[$i];
}
return ($sum);
}
$start = microtime(true);
for ($x = 0 ; $x < 100; $x++){
$sum = sum($data, $max);
}
$end = microtime(true);
echo "Time: ".($end - $start)." s\n";
/* Run times:
# PASS BY MODIFIED? Time
- ------- --------- ----
1 value no 56 us
2 reference no 58 us
Conclusions:
1. PHP is already smart about zero-copy / copy-on-write. A function call does NOT copy the data unless
it needs to; the data is
only copied on write. That's why #1 and #2 take similar times, whereas #3 takes 2 million times
longer than #4.
[You never need to use &$array to ask the compiler to do a zero-copy optimisation; it can work that
out for itself.]
2. You do use &$array to tell the compiler "it is OK for the function to over-write my argument in
place, I don't need the original
any more." This can make a huge difference to performance when we have large amounts of memory to
copy.
(This is the only way it is done in C, arrays are always passed as pointers)
3. The other use of & is as a way to specify where data should be *returned*. (e.g. as used by exec() ).
(This is a C-like way of passing pointers for outputs, whereas PHP functions normally return complex
types, or multiple answers
in an array)
4. It's unhelpful that only the function definition has &. The caller should have it, at least as
syntactic sugar. Otherwise
it leads to unreadable code: because the person reading the function call doesn't expect it to pass
by reference. At the moment,
it's necessary to write a by-reference function call with a comment, thus:
$sum = sum($data,$max); //warning, $data passed by reference, and may be modified.
5. Sometimes, pass by reference could be at the choice of the caller, NOT the function definitition. PHP
doesn't allow it, but it
would be meaningful for the caller to decide to pass data in as a reference. i.e. "I'm done with the
variable, it's OK to stomp
on it in memory".
*/
?>
Editor's note: what is expected here by the parser is a non-evaluated expression. An operand and
two constants requires evaluation, which is not done by the parser. However, this feature is
included as of PHP 5.6.0. See this page for more information: http://php.net/migration56.new-
features#migration56.new-features.const-scalar-exprs
--------
"The default value must be a constant expression" is misleading (or even wrong). PHP 5.4.4 fails to
parse this function definition:
This yields a " PHP Parse error: syntax error, unexpected '|', expecting ')' " although
ENT_COMPAT|ENT_HTML401 is certainly what a compiler-affine person would call a "constant
expression".
The obvious workaround is to use a single special value ($flags = NULL) as the default, and to set it
to the desired value in the function's body (if ($flags === NULL) { $flags = ENT_COMPAT |
ENT_HTML401; }).
John 15-Nov-2006 03:20
This might be documented somewhere OR obvious to most, but when passing an argument by
reference (as of PHP 5.04) you can assign a value to an argument variable in the function call. For
example:
outputs 0 (false)
In function calls, PHP clearly distinguishes between missing arguments and present but empty
arguments. Thus:
<?php
function f( $x = 4 ) { echo $x . "\\n"; }
f(); // prints 4
f( null ); // prints blank line
f( $y ); // $y undefined, prints blank line
?>
The utility of the optional argument feature is thus somewhat diminished. Suppose you want to
call the function f many times from function g, allowing the caller of g to specify if f should be called
with a specific value or with its default value:
<?php
function f( $x = 4 ) {echo $x . "\\n"; }
// option 1: cut and paste the default value from f's interface into g's
function g( $x = 4 ) { f( $x ); f( $x ); }
The best approach, it seems to me, is to always use a sentinel like null as the default value of an
optional argument. This way, callers like g and g's clients have many options, and furthermore,
callers always know how to omit arguments so they can omit one in the middle of the parameter
list.
<?php
function f( $x = null ) { if ( !isset( $x ) ) $x = 4; echo $x . "\\n"; }
function g( $x = null ) { f( $x ); f( $x ); }
f(); // prints 4
f( null ); // prints 4
f( $y ); // $y undefined, prints 4
g(); // prints 4 twice
g( null ); // prints 4 twice
g( 5 ); // prints 5 twice
?>
However, what happens if you wanted to pass an undefined number of references, i.e., something
like:
myfunction(&$arg1, &$arg2, ..., &$arg-n);?
This doesn't work in PHP 5 anymore.
In the following code I tried to amend this by using the array() language-construct as the actual
argument in the
call to the function.
<?php
function aa ($A) {
// This function increments each
// "pseudo-argument" by 2s
foreach ($A as &$x) {
$x += 2;
}
}
$x = 1; $y = 2; $z = 3;
Sergio.
Returning values
Values are returned by using the optional return statement. Any type may be returned,
including arrays and objects. This causes the function to end its execution immediately and
pass control back to the line from which it was called. See return for more information.
Note:
If the return is omitted the value NULL will be returned.
Use of return
<?php
function square($num)
{
return $num * $num;
}
echo square(4); // outputs '16'.
?>
A function can not return multiple values, but similar results can be obtained by returning
an array.
<?php
function small_numbers()
{
return array (0, 1, 2);
}
list ($zero, $one, $two) = small_numbers();
?>
To return a reference from a function, use the reference operator & in both the function
declaration and when assigning the returned value to a variable:
<?php
function &returns_reference()
{
return $someref;
}
<?php
class Child{}
var_dump(getChilds());
// Returns: Parse error: syntax error, unexpected '[', expecting '{'
?>
We have to use:
<?php
class Child{}
var_dump(getChilds());
// Returns:
/*
array (size=2)
0 =>
object(Child)[168]
1 =>
object(Child)[398]
*/
?>
Only one return type can be specified (but prefacing with ? allows null).
Return values of a type different to that specified are silently converted with sometimes perplexing
results. These can be tedious to find and will need rewriting, along with calling code.
Declare strict types using "declare(strict_types=1);" and an error will be generated, saving much
head-scratching.
<?php
class A {
public function f ($a)
{
return 1;
}
}
class B extends A {
public function f ($a): int // + return type, OK
{
return 1;
}
}
class C extends A {
public function f (int $a) // + argument type, WARNING
{
return 1;
}
}
?>
PHP 7.1 allows for void and null return types by preceding the type declaration with a ? -- (e.g.
function canReturnNullorString(): ?string)
<?php
function fileOpen(string $fileName, string $mode): resource
{
$handle = fopen($fileName, $mode);
if ($handle !== false)
{
return $handle;
}
}
Errors with:
Fatal error: Uncaught TypeError: Return value of fileOpen() must be an instance of resource,
resource returned.
<?php
function ret_void(): void {
// do something but no return any value
// if needs to break fn exec for any reason simply write return;
if (...) {
return; // break
// return null; // even this NO!
}
$db->doSomething();
// no need return call anymore
}
function ret_nullable() ?int {
if (...) {
return 123;
} else {
return null; // MUST!
}
}
?>
Note: the function does not have "alternative syntax" as if/endif, while/endwhile, and colon (:) here
is used to define returning type and not to mark where the block statement begins.
ryan dot jentzsch at gmail dot com 30-Aug-2015 06:12
<?php
declare(strict_types=1);
Output:
7
Process finished with exit code 139
Developers with a C background may expect pass by reference semantics for arrays. It may be
surprising that pass by value is used for arrays just like scalars. Objects are implicitly passed by
reference.
<?php
class Obj {
public $x;
}
function obj_inc_x($obj) {
$obj->x++;
return $obj;
}
$obj2 = obj_inc_x($obj);
obj_inc_x($obj2);
function scalar_inc_x($x) {
$x++;
return $x;
}
$x = 1;
$x2 = scalar_inc_x($x);
scalar_inc_x($x2);
# (3) You have to force pass by reference and return by reference on scalars
function &scalar_ref_inc_x(&$x) {
$x++;
return $x;
}
$x = 1;
$x2 =& scalar_ref_inc_x($x); # Need reference here as well as the function sig
scalar_ref_inc_x($x2);
function array_inc_x($array) {
$array{'x'}++;
return $array;
}
$array = array();
$array['x'] = 1;
$array2 = array_inc_x($array);
array_inc_x($array2);
# (5) You have to force pass by reference and return by reference on arrays
function &array_ref_inc_x(&$array) {
$array{'x'}++;
return $array;
}
$array = array();
$array['x'] = 1;
$array2 =& array_ref_inc_x($array); # Need reference here as well as the function sig
array_ref_inc_x($array2);
Be careful about using "do this thing or die()" logic in your return lines. It doesn't work as you'd
expect:
<?php
function myfunc1() {
return('thingy' or die('otherthingy'));
}
function myfunc2() {
return 'thingy' or die('otherthingy');
}
function myfunc3() {
return('thingy') or die('otherthingy');
}
function myfunc4() {
return 'thingy' or 'otherthingy';
}
function myfunc5() {
$x = 'thingy' or 'otherthingy'; return $x;
}
echo myfunc1(). "\n". myfunc2(). "\n". myfunc3(). "\n". myfunc4(). "\n". myfunc5(). "\n";
?>
i.e.
<?php
function &testRet()
{
return NULL;
}
Variable functions won't work with language constructs such as echo, print, unset(), isset(),
empty(), include, require and the like. Utilize wrapper functions to make use of any of these
constructs as variable functions.
<?php
function foo() {
echo "In foo()<br />\n";
}
$func = 'foo';
$func(); // This calls foo()
$func = 'bar';
$func('test'); // This calls bar()
$func = 'echoit';
$func('test'); // This calls echoit()
?>
Object methods can also be called with the variable functions syntax.
<?php
class Foo
{
function Variable()
{
$name = 'Bar';
$this->$name(); // This calls the Bar() method
}
function Bar()
{
echo "This is Bar";
}
}
?>
When calling static methods, the function call is stronger than the static property operator:
<?php
class Foo
{
static $variable = 'static property';
static function Variable()
{
echo 'Method Variable called';
}
}
echo Foo::$variable; // This prints 'static property'. It does need a $variable in this scope.
$variable = "Variable";
Foo::$variable(); // This calls $foo->Variable() reading $variable in this scope.
?>
<?php
class Foo
{
static function bar()
{
echo "bar\n";
}
function baz()
{
echo "baz\n";
}
}
See Also
is_callable()
call_user_func()
function_exists()
variable variables
If you are here looking for a function reference, this is NOT how to do it:
<?php
function func1(){ echo "hell0 1";}
$choice = func1; // no quotes
?>
It works, but $choice is not what you might think, a reference to a function. It is simply the name
of the function as a string, written without (!) quotes.
So calling
<?php
$choice()
?>
is a variable-function for both cases, calling it by its name, not by reference.
Now you can pass around the function like a first class object
<?php
$choice = $func1;
?>
or
<?php
$choice = $func2;
?>
and call it
<?php
$choice();
?>
If you want to pass around a class method, use the "Complex callables" from the manual, above. It's
a call by name (not a reference), but since you can include the object you can still get the flexibility
you want:
<?php
class C {
function k(){ echo "inside k";}
function j(){ echo "inside j"; return array($this,"k");}};
?>
You can use $this as the object in the first element of the array.
<?php
$c = new C;
$c->k();
inside k
$func = $c->j();
inside j
?>
And now, le moment supreme:
<?php
$func();
inside k
?>
I credit this expanded work to this person: tatarynowicz at gmail dot com;
without them I would not have gotten here.
*/
interface iface_dynamic_members{
//Use of this interface enables type-hinting for objects that implement it.
public function __call($name, $args);
public function __set($name, $value);
public function quietly_fail():bool;
}
trait trait_has_dynamic_members{
//Implementing these magic methods in the form of a trait, frees the client object up
//so it can still inherit from a parent-class.
public function __call($name, $args) {
if (is_callable($this->$name)) {
return call_user_func($this->$name, $args);
}
else {
//Your dynamic-membered object can declare itself as willing to ignore non-existent method
calls or not.
if($this->quietly_fail()===true){
echo 'Method does not exist, but I do not mind.';
}else{
echo 'Method does not exist, I consider this a bug.';
}
}
}
public function __set($name, $value) {
$this->$name = is_callable($value) ? $value->bindTo($this, $this): $value; //Assignment using
ternary operator.
}
}
abstract class MBR_ATTR{
//A class full of attributes that objects can take on; abstract since not to be instantiated (If I
could make it "final" as well, I would).
public static function is_a_walker(iface_dynamic_members $obj, ?string $walker_type='normal pace'){
$obj->walker_type = $walker_type;
$obj->walker_walk = function() {
return "I am walking {$this->walker_type}.";
};
}
public static function is_a_runner(iface_dynamic_members $obj, string $runner_type){
$obj->runner_type = $runner_type;
$obj->runner_run = function() {
return "I am running {$this->runner_type}.";
};
self::is_a_walker($obj); //If can run, also can walk.
}
}
class cls_partly_dynamic implements iface_dynamic_members{
use trait_has_dynamic_members;
public function quietly_fail():bool{
return true;
}
}
// Report all errors except E_NOTICE
error_reporting(E_ALL & ~E_NOTICE); //Enable all error-reporting except notices.
//----
//config runner object...
$obj_runner = new cls_partly_dynamic();
MBR_ATTR::is_a_runner($obj_runner, 'fast');
$obj_runner->runner_type = 'a bit slow';
//----
//config walker object...
$obj_walker = new cls_partly_dynamic();
MBR_ATTR::is_a_walker($obj_walker, 'slow');
$obj_walker->walker_type = 'super fast';
//----
//Do stuff...
echo 'walker in action...' . '<br>';
echo $obj_walker->walker_walk() . '<br>';
echo '<br>';
echo 'runner in action...' . '<br>';
echo $obj_runner->walker_walk() . '<br>';
echo $obj_runner->runner_run() . '<br>';
echo $obj_runner->xxx() . '<br>'; //Try calling a non-existent method.
//I would agree that the above approach/technique is not always ideal, particulary due to the loss of
code-completion in your
//IDE of choice; I would tend to use this approach for dynamic-programming in response to the user
dictating processing steps via a UI.
?>
While the documentation suggests that the use of a constant is similar to the use of a variable,
there is an exception regarding variable functions. You cannot use a constant as the function name
to call a variable function.
$call = DEBUGME;
$call('abc'); // does the job
But you can use a constant as an argument to a function. Here's a simple workaround when you need to
call a variable constant function:
This makes sense to me to hide API's and/or long (complicated) static calls.
Enjoy!
<?php
namespace Project\TestClass;
class Test {
static function funcToCall() {
return "test";
}
}
?>
You must call it as:
<?php
namespace Project\OtherTestClass;
class OtherTest {
static function callOtherFunc() {
$func = '\Project\TestClass::funcToCall';
$func();
}
}
?>
and not:
<?php
class OtherTest {
static function callOtherFunc() {
$func = 'TestClass::funcToCall';
$func();
}
}
?>
Make an array of two entries where the 0th entry is the name of the class to be invoked ('self' and
'parent' work as well) and the 1st entry is the name of the function. Basically, a 'callback' variable
is either a string (the name of the function) or an array (0 => 'className', 1 => 'functionName').
Then, to call that function, you can use either call_user_func() or call_user_func_array(). Examples:
<?php
class A {
protected $a;
protected $c;
function __construct() {
$this->a = array('self', 'a');
$this->c = array('self', 'c');
}
function d() {
call_user_func_array($this->c, func_get_args());
}
function e() {
call_user_func($this->c, func_get_arg(0));
}
class B extends A {
function __construct() {
$this->a = array('parent', 'a');
$this->c = array('self', 'c');
}
function d() {
call_user_func_array($this->c, func_get_args());
}
function e() {
call_user_func($this->c, func_get_args());
}
$a =& new A;
$b =& new B;
$i = 0;
A::a('index', $i);
$a->b('index', $i);
$a->c('string');
$a->d('string');
$a->e('string');
# etc.
?>
Reading and understanding a function's prototype is explained within the manual section
titled how to read a function definition. It's important to realize what a function returns or if
a function works directly on a passed in value. For example, str_replace() will return the
modified string while usort() works on the actual passed in variable itself. Each manual page
also has specific information for each function like information on function parameters,
behavior changes, return values for both success and failure, and availability information.
Knowing these important (yet often subtle) differences is crucial for writing correct PHP code.
Note: If the parameters given to a function are not what it expects, such as passing an array where a string is
expected, the return value of the function is undefined. In this case it will likely return NULL but this is just a
convention, and cannot be relied upon.
See Also
function_exists()
the function reference
get_extension_funcs()
dl()
User Contributed Notes
There are no user contributed notes for this page.
Anonymous functions
Anonymous functions, also known as closures, allow the creation of functions which have no
specified name. They are most useful as the value of callable parameters, but they have
many other uses.
<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// outputs helloWorld
?>
Closures can also be used as the values of variables; PHP automatically converts such
expressions into instances of the Closure internal class. Assigning a closure to a variable
uses the same syntax as any other assignment, including the trailing semicolon:
<?php
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
Closures may also inherit variables from the parent scope. Any such variables must be
passed to the use language construct. As of PHP 7.1, these variables must not include
superglobals, $this, or variables with the same name as a parameter.
<?php
$message = 'hello';
// No "use"
$example = function () {
var_dump($message);
};
$example();
// Inherit $message
$example = function () use ($message) {
var_dump($message);
};
$example();
// Reset message
$message = 'hello';
// Inherit by-reference
$example = function () use (&$message) {
var_dump($message);
};
$example();
As of PHP 8.0.0, the list of scope-inherited variables may include a trailing comma, which
will be ignored.
Inheriting variables from the parent scope is not the same as using global variables. Global
variables exist in the global scope, which is the same no matter what function is executing.
The parent scope of a closure is the function in which the closure was declared (not
necessarily the function it was called from). See the following example:
<?php
// A basic shopping cart which contains a list of added products
// and the quantity of each product. Includes a method which
// calculates the total price of the items in the cart using a
// closure as a callback.
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
$callback =
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
}
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
?>
object(Test)#1 (0) {
}
When declared in the context of a class, the current class is automatically bound to it,
making $this available inside of the function's scope. If this automatic binding of the current
class is not wanted, then static anonymous functions may be used instead.
Anonymous functions may be declared statically. This prevents them from having the
current class automatically bound to them. Objects may also not be bound to them at
runtime.
<?php
class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();
?>
<?php
Anonymous functions may not close over superglobals, $this, or any variable with the same name as a
7.1.0
parameter.
Notes
Note: It is possible to use func_num_args(), func_get_arg(), and func_get_args() from within a closure.
<?php
class Foo {
public function bar() {
static $anonymous = null;
if ($anonymous === null) {
// Expression is not allowed as static initializer workaround
$anonymous = function () {
return $this;
};
}
return $anonymous();
}
}
$a = new Foo();
$b = new Foo();
var_dump($a->bar() === $a); // True
var_dump($b->bar() === $a); // Also true
?>
In a static anonymous function, $this will be the value of whatever object instance that
method was called on first.
To get the behaviour you're probably expecting, you need to pass the $this context into
the function.
<?php
class Foo {
public function bar() {
static $anonymous = null;
if ($anonymous === null) {
// Expression is not allowed as static initializer workaround
$anonymous = function (self $thisObj) {
return $thisObj;
};
}
return $anonymous($this);
}
}
$a = new Foo();
$b = new Foo();
var_dump($a->bar() === $a); // True
var_dump($b->bar() === $a); // False
?>
Creating new lambda with function() { ... }; expression creates new instance of its static variables. Assigning a
lambda to a variable does not create a new instance. A lambda is object of class Closure, and assigning
lambdas to variables has the same semantics as assigning object instance to variables.
Example script: $a and $b have separate instances of static variables, thus produce different output. However
$b and $c share their instance of static variables - because $c is refers to the same object of class Closure as
$b - thus produce the same output.
#!/usr/bin/env php
<?php
$a('test AAA');
$b('test BBB');
$c('test CCC'); # this overwrites content held by $b, because it refers to the same object
<?php
$type = 'number';
var_dump( ...( function() use ($type) {
if ($type=='number') return [1,2,3];
else if ($type=='alphabet') return ['a','b','c'];
} )() );
?>
<?php
$count = 1;
$add = function($count) use (&$add){
$count += 1;
if($count < 10) $count = $add($count); //recursive calling
return $count;
};
echo $add($count); //Will output 10 as expected
?>
I decided to compare a single, saved closure against constantly creating the same
anonymous closure on every loop iteration. And I tried 10 million loop iterations, in PHP
7.0.14 from Dec 2016. Result:
new anonymous closure created each time (10000000 iterations): 2.8460240364075 seconds
In other words, over the course of 10 million iterations, creating the closure again
during every iteration only added a total of "1.459 seconds" to the runtime. So that
means that every creation of a new anonymous closure takes about 146 nanoseconds on my 7
years old dual-core laptop. I guess PHP keeps a cached "template" for the anonymous
function and therefore doesn't need much time to create a new instance of the closure!
So you do NOT have to worry about constantly re-creating your anonymous closures over and
over again in tight loops! At least not as of PHP 7! There is absolutely NO need to save
an instance in a variable and re-use it. And not being restricted by that is a great
thing, because it means you can feel free to use anonymous functions exactly where they
matter, as opposed to defining them somewhere else in the code. :-)
class Test
{
private $closure;
new Test;
echo "finished\n";
/*
* Result in PHP 5.3:
* ------------------
* destructed
* finished
*
* Result since PHP 5.4:
* ---------------------
* finished
* destructed
*/
?>
To circumvent this, you can instantiate the Closure in a static method:
<?php
?>
<?php
$value = 0;
$fn = function &() use (&$value) { return $value; };
$x =& $fn();
var_dump($x, $value); // 'int(0)', 'int(0)'
++$x;
var_dump($x, $value); // 'int(1)', 'int(1)'
public test;
$f = new foo();
$f->test();
?>
public test;
public function __construct(){
$this->test = function($a) {
print "$a\n";
};
}
/*
* An example showing how to use closures to implement a Python-like decorator
* pattern.
*
* My goal was that you should be able to decorate a function with any
* other function, then call the decorated function directly:
*
* Define function: $foo = function($a, $b, $c, ...) {...}
* Define decorator: $decorator = function($func) {...}
* Decorate it: $foo = $decorator($foo)
* Call it: $foo($a, $b, $c, ...)
*
* This example show an authentication decorator for a service, using a simple
* mock session and mock service.
*/
session_start();
/*
* Define an example decorator. A decorator function should take the form:
* $decorator = function($func) {
* return function() use $func) {
* // Do something, then call the decorated function when needed:
* $args = func_get_args($func);
* call_user_func_array($func, $args);
* // Do something else.
* };
* };
*/
$authorise = function($func) {
return function() use ($func) {
if ($_SESSION['is_authorised'] == true) {
$args = func_get_args($func);
call_user_func_array($func, $args);
}
else {
echo "Access Denied";
}
};
};
/*
* Define a function to be decorated, in this example a mock service that
* need to be authorised.
*/
$service = function($foo) {
echo "Service returns: $foo";
};
/*
* Decorate it. Ensure you replace the origin function reference with the
* decorated function; ie just $authorise($service) won't work, so do
* $service = $authorise($service)
*/
$service = $authorise($service);
/*
* Establish mock authorisation, call the service; should get
* 'Service returns: test 1'.
*/
$_SESSION['is_authorised'] = true;
$service('test 1');
/*
* Remove mock authorisation, call the service; should get 'Access Denied'.
*/
$_SESSION['is_authorised'] = false;
$service('test 2');
?>
So you will need to explicitly pass them in by reference if your closure cares about
their contents over time:
<?php
$result = 0;
$one = function()
{ var_dump($result); };
$result++;
$one(); // outputs NULL: $result is not in scope
$two(); // outputs int(0): $result was copied
$three(); // outputs int(1)
?>
Another less trivial example with objects (what I actually tripped up on):
<?php
//set up variable in advance
$myInstance = null;
$broken(); // will never do anything: $myInstance will ALWAYS be null inside this closure.
$working(); // will call doSomething if $myInstance is instantiated
?>
$some_var1="1";
$some_var2="2";
http://www.php.net/manual/en/function.call-user-func.php
http://www.php.net/manual/en/function.call-user-func-array.php
If you're wondering if $some_var1 and $some_var2 are still visible by using the
call_user_func, yes, they are available.
The most useful tool in this snippet is the requesting_class() function that will tell
you which class is responsible for executing the current Closure().
Overview:
-----------------------
Successfully find calling object reference.
Successfully call $this(__invoke);
Successfully reference $$this->name;
Successfully call call_user_func(array($this, 'method'))
<?php
function requesting_class()
{
foreach(debug_backtrace(true) as $stack){
if(isset($stack['object'])){
return $stack['object'];
}
}
class Person
{
public $name = '';
public $head = true;
public $feet = true;
public $deflected = false;
$this->feet = false;
}
}
$p = new Person('Bob');
$p->customAttack =
function(){
#$this->head = 0; //** FATAL ERROR: Using $this when not in object context
$$this->head = 0; // Successfully sets value
};
print_r($p);
$p->shoot();
print_r($p);
die();
?>
<?php
class Fun
{
protected function debug($message)
{
echo "DEBUG: $message\n";
}
// Ah-Ha!
public function __call($method, $args = array())
{
if(is_callable(array($this, $method)))
return call_user_func_array(array($this, $method), $args);
}
}
?>
<?php
$isAClosure = is_callable($thing) && is_object($thing);
?>
Since a property can be also an anonymous function as of PHP 5.3.0, an oddity arises when
they share the same name, not meaning that there would be any conflict.
<?php
class MyClass {
const member = 1;
public $member;
header("Content-Type: text/plain");
var_dump(MyClass::member); // int(1)
var_dump($myObj->member); // object(Closure)#2 (0) {}
var_dump($myObj->member()); // string(15) "method 'member'"
$myMember = $myObj->member;
var_dump($myMember()); // string(27) "anonymous function 'member'"
?>
That means, regular method invocations work like expected and like before. The anonymous
function instead, must be retrieved into a variable first (just like a property) and can
only then be invoked.
Best regards,
Arrow Functions
Arrow functions were introduced in PHP 7.4 as a more concise syntax for anonymous
functions.
Both anonymous functions and arrow functions are implemented using the Closure class.
Arrow functions support the same features as anonymous functions, except that using
variables from the parent scope is always automatic.
When a variable used in the expression is defined in the parent scope it will be implicitly
captured by-value. In the following example, the functions $fn1 and $fn2 behave the same
way.
<?php
$y = 1;
var_export($fn1(3));
?>
Example #2 Arrow functions capture variables by value automatically, even when nested
<?php
$z = 1;
$fn = fn($x) => fn($y) => $x * $y + $z;
// Outputs 51
var_export($fn(5)(10));
?>
Similarly to anonymous functions, the arrow function syntax allows arbitrary function
signatures, including parameter and return types, default values, variadics, as well as by-
reference passing and returning. All of the following are valid examples of arrow functions:
<?php
?>
Arrow functions use by-value variable binding. This is roughly equivalent to performing a
use($x) for every variable $x used inside the arrow function. A by-value binding means that
it is not possible to modify any values from the outer scope. Anonymous functions can be
used instead for by-ref bindings.
Example #4 Values from the outer scope cannot be modified by arrow functions
<?php
$x = 1;
$fn = fn() => $x++; // Has no effect
$fn();
var_export($x); // Outputs 1
?>
Changelog
Version Description
Notes
Note: It is possible to use func_num_args(), func_get_arg(), and func_get_args() from within an arrow function.
User Contributed Notes
dexen dot devries at gmail dot com 03-Aug-2020 07:39
Beware compact() not being able to access (import) variables from external scope (known
in versions: 7.4.0, 7.4.8) (bug: https://bugs.php.net/bug.php?id=78970).
A workaround is available - use the variable directly; this will cause it to be imported
into the arrow function's namespace and make it available to the compact() too.
<?php
$aa = 111;
$accessing_variable_works = fn($bb) => [ $aa, $bb ];
$compact_is_broken = fn($bb) => compact('aa', 'bb');
$compact_can_work_with_workaround = fn($bb) => compact('aa', 'bb') + ['workaround' => $aa];
var_dump($accessing_variable_works(333));
var_dump($compact_is_broken(555));
var_dump($compact_can_work_with_workaround(777));
?>
result:
array(2) {
[0]=>
int(111)
[1]=>
int(333)
}
PHP Notice: compact(): Undefined variable: aa in
/home/m/vlt/guitar/tlb/s/public_html/index.php on line 9
array(1) {
["bb"]=>
int(555)
}
array(3) {
["aa"]=>
int(111)
["bb"]=>
int(777)
["workaround"]=>
int(111)
}
<?php
$x = 1;
$fn = fn() => $x++; // Has no effect
$fn();
var_export($x); // Outputs 1
?>
Here we can use reference variable in fn(&$x) and pass the value from function call
$fn($x) so that we will get the output as expected with out using Anonymous functions.
Example:
<?php
$x = 1;
$fn = fn(&$x) => $x++;
$fn($x);
var_export($x);
?>
But here it will not take values from parent scope automatically but we have to pass them
explicitly.