0% found this document useful (0 votes)
35 views

Functions PHP

Functions PHP

Uploaded by

Poorna28
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
35 views

Functions PHP

Functions PHP

Uploaded by

Poorna28
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 50

Functions

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:

Example #1 Pseudo code to demonstrate function uses

<?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

See also the Userland Naming Guide.

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.

Example #2 Conditional functions

<?php

$makefoo = true;

/* We can't call foo() from here


since it doesn't exist yet,
but we can call bar() */

bar();

if ($makefoo) {
function foo()
{
echo "I don't exist until program execution reaches me.\n";
}
}

/* Now we can safely call foo()


since $makefoo evaluated to true */

if ($makefoo) foo();

function bar()
{
echo "I exist immediately upon program start.\n";
}

?>

Example #3 Functions within functions

<?php
function foo()
{
function bar()
{
echo "I don't exist until foo() is called.\n";
}
}

/* We can't call bar() yet


since it doesn't exist. */

foo();

/* Now we can call bar(),


foo()'s processing has
made it accessible. */

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.

It is possible to call recursive functions in PHP.

Example #4 Recursive functions

<?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.

User Contributed Notes


There are no user contributed notes for this page.

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.

Example #1 Passing arrays to functions

<?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.

Example #2 Function Argument List with trailing Comma

<?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.
)
{
// ...
}
?>

Passing arguments by reference

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.

To have an argument to a function always passed by reference, prepend an ampersand (&)


to the argument name in the function definition:

Example #3 Passing function parameters 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.'
?>

Default argument values

A function may define C++-style default values for scalar arguments as follows:

Example #4 Use of default parameters in functions

<?php
function makecoffee($type = "cappuccino")
{
return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");
?>

The above example will output:

Making a cup of cappuccino.


Making a cup of .
Making a cup of espresso.

PHP also allows the use of arrays and the special type NULL as default values, for example:

Example #5 Using non-scalar types as default values


<?php
function makecoffee($types = array("cappuccino"), $coffeeMaker = NULL)
{
$device = is_null($coffeeMaker) ? "hands" : $coffeeMaker;
return "Making a cup of ".join(", ", $types)." with $device.\n";
}
echo makecoffee();
echo makecoffee(array("cappuccino", "lavazza"), "teapot");
?>

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:

Example #6 Incorrect usage of default function arguments

<?php
function makeyogurt($type = "acidophilus", $flavour)
{
return "Making a bowl of $type $flavour.\n";
}

echo makeyogurt("raspberry"); // won't work as expected


?>

The above example will output:

Warning: Missing argument 2 in call to makeyogurt() in


/usr/local/etc/httpd/htdocs/phptest/functest.html on line 41
Making a bowl of raspberry .

Now, compare the above with this:

Example #7 Correct usage of default function arguments

<?php
function makeyogurt($flavour, $type = "acidophilus")
{
return "Making a bowl of $type $flavour.\n";
}

echo makeyogurt("raspberry"); // works as expected


?>

The above example will output:

Making a bowl of acidophilus raspberry.

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:

Example #8 Using ... to access variable arguments

<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}

echo sum(1, 2, 3, 4);


?>

The above example will output:

10

... can also be used when calling functions to unpack an array or Traversable variable or
literal into the argument list:

Example #9 Using ... to provide arguments

<?php
function add($a, $b) {
return $a + $b;
}

echo add(...[1, 2])."\n";

$a = [1, 2];
echo add(...$a);
?>

The above example will output:

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.

Example #10 Type declared variable arguments

<?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';

// This will fail, since null isn't a DateInterval object.


echo total_intervals('d', null);
?>

The above example will output:

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 (&).

Older versions of PHP

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:

Example #11 Accessing variable arguments in old PHP versions

<?php
function sum() {
$acc = 0;
foreach (func_get_args() as $n) {
$acc += $n;
}
return $acc;
}

echo sum(1, 2, 3, 4);


?>
The above example will output:

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);
}
}
?>

dmitry dot balabka at gmail dot com 13-Nov-2018 09:47

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;

public function __construct(parent $original)


{
$this->original = $original;
}

protected function getOriginal(): parent


{
return $this->original;
}
}

class Implementation extends ParentClass


{
use ClassTrait;

public function callSomeMethod()


{
$this->getOriginal()->someMethod();
}
}

$obj = new Implementation(new ParentClass());


$obj->callSomeMethod();
?>

Outputs:
Some method called

boan dot web at outlook dot com 08-Feb-2018 11:27

Quote:

"The declaration can be made to accept NULL values if the default value of the parameter is set to NULL."

But you can do this (PHP 7.1+):

<?php
function foo(?string $bar) {
//...
}

foo(); // Fatal error


foo(null); // Okay
foo('Hello world'); // Okay
?>

igorsantos07 at gmail dot com 27-Dec-2017 05:06

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
?>

info at keraweb dot nl 21-Sep-2017 09:25

You can use a class constant as a default parameter.

<?php

class A {
const FOO = 'default';
function bar( $val = self::FOO ) {
echo $val;
}
}

$a = new A();
$a->bar(); // Will echo "default"

Hayley Watson 30-Aug-2017 11:41

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]];

$result = array_merge(...$array1); // Legal, of course: $result == [1,2,3];


$result = array_merge($array2, ...$array1); // $result == [4,1,2,3]
$result = array_merge(...$array1, $array2); // Fatal error: Cannot use positional argument after
argument unpacking.
$result = array_merge(...$array1, ...$array3); // Legal! $result == [1,2,3,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.

Hayley Watson 16-Aug-2017 12:50


If you use ... in a function's parameter list, you can use it only once for obvious reasons. Less obvious is that it has to be
on the LAST parameter; as the manual puts it: "You may specify normal positional arguments BEFORE the ... token.
(emphasis mine).

<?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.

gabriel at figdice dot org 11-Aug-2016 07:05

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;

function f ( $o ) // Notice the absence of &


{
$o->prop ++;
}

f($x);

echo $x->prop; // shows: 2


?>

This is different for arrays:

<?php
$y = [ 'prop' => 1 ];

function g( $a )
{
$a['prop'] ++;
echo $a['prop']; // shows: 2
}

g($y);

echo $y['prop']; // shows: 1


?>

catman at esteticas dot se 07-Feb-2016 01:06

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

php at richardneill dot org 28-Mar-2015 07:24

To experiment on performance of pass-by-reference and pass-by-value, I used this script.


Conclusions are below.

#!/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);
}

$max = 1E7 //10 M data points.


$data = range(0,$max,1);

$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

3 valuue yes 129 s


4 reference yes 66 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".
*/
?>

Horst Schirmeier 08-Jan-2014 11:58

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:

function htmlspecialchars_latin1($s, $flags = ENT_COMPAT | ENT_HTML401) {}

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:

function my_function($arg1, &$arg2) {


if ($arg1 == true) {
$arg2 = true;
}
}
my_function(true, $arg2 = false);
echo $arg2;
outputs 1 (true)

my_function(false, $arg2 = false);


echo $arg2;

outputs 0 (false)

jcaplan at bogus dot amazon dot com 09-Mar-2006 03:11

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 ); }

// option 2: branch based on input to g


function g( $x = null ) { if ( !isset( $x ) ) { f(); f() } else { f( $x ); f( $x ); } }
?>

Both options suck.

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

?>

Sergio Santana: ssantana at tlaloc dot imta dot mx 31-Oct-2005 02:59


PASSING A "VARIABLE-LENGTH ARGUMENT LIST OF REFERENCES" TO A FUNCTION
As of PHP 5, Call-time pass-by-reference has been deprecated, this represents no problem in most cases, since instead of
calling a function like this:
myfunction($arg1, &$arg2, &$arg3);

you can call it


myfunction($arg1, $arg2, $arg3);

provided you have defined your function as


function myfuncion($a1, &$a2, &$a3) { // so &$a2 and &$a3 are
// declared to be refs.
... <function-code>
}

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;

aa(array(&$x, &$y, &$z));


echo "--$x--$y--$z--\n";
// This will output:
// --3--4--5--
?>

I hope this is useful.

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

Example #1 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.

Example #2 Returning an array to get multiple values

<?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:

Example #3 Returning a reference from a function

<?php
function &returns_reference()
{
return $someref;
}

$newref =& returns_reference();


?>

For more information on references, please check out References Explained.

User Contributed Notes


php(@)genjo(DOT)fr 21-Oct-2019 08:40
Declaring a collection of objects as return type is not implemented and forbidden:

<?php
class Child{}

function getChilds(): Child[]


{
return [(new Child()), (new Child())];
}

var_dump(getChilds());
// Returns: Parse error: syntax error, unexpected '[', expecting '{'
?>

We have to use:
<?php
class Child{}

function getChilds(): array


{
return [(new Child()), (new Child())];
}

var_dump(getChilds());
// Returns:
/*
array (size=2)
0 =>
object(Child)[168]
1 =>
object(Child)[398]
*/
?>

Idem for function parameter:


<?php
function setChilds(Child[] $childs){}
// Not allowed

function setChilds(array $childs){}


// Allowed
?>

Berniev 07-May-2018 02:20

Be careful when introducing return types to your code.

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.

zored dot box at gmail dot com 26-Feb-2018 03:54


You may specify child return type if there is no parent:

<?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;
}
}
?>

ryan dot jentzsch at gmail dot com 02-Jan-2017 06:40

PHP 7.1 allows for void and null return types by preceding the type declaration with a ? -- (e.g.
function canReturnNullorString(): ?string)

However resource is not allowed as a return type:

<?php
function fileOpen(string $fileName, string $mode): resource
{
$handle = fopen($fileName, $mode);
if ($handle !== false)
{
return $handle;
}
}

$resourceHandle = fileOpen("myfile.txt", "r");


?>

Errors with:
Fatal error: Uncaught TypeError: Return value of fileOpen() must be an instance of resource,
resource returned.

k-gun !! mail 19-Dec-2016 10:50


With 7.1, these are possible yet;

<?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!
}
}
?>

Vidmantas Maskoliunas 17-Apr-2016 10:58

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 7 return types if specified can not return a null.


For example:

<?php
declare(strict_types=1);

function add2ints(int $x, int $y):int


{
$z = $x + $y;
if ($z===0)
{
return null;
}
return $z;
}
$a = add2ints(3, 4);
echo is_null($a) ? 'Null' : $a;
$b = add2ints(-2, 2);
echo is_null($b) ? 'Null' : $b;
exit();

Output:
7
Process finished with exit code 139

rstaveley at seseit dot com 29-Aug-2010 01:26

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

# (1) Objects are always passed by reference and returned by reference

class Obj {
public $x;
}

function obj_inc_x($obj) {
$obj->x++;
return $obj;
}

$obj = new Obj();


$obj->x = 1;

$obj2 = obj_inc_x($obj);
obj_inc_x($obj2);

print $obj->x . ', ' . $obj2->x . "\n";

# (2) Scalars are not passed by reference or returned as such

function scalar_inc_x($x) {
$x++;
return $x;
}

$x = 1;

$x2 = scalar_inc_x($x);
scalar_inc_x($x2);

print $x . ', ' . $x2 . "\n";

# (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);

print $x . ', ' . $x2 . "\n";

# (4) Arrays use pass by value sematics just like scalars

function array_inc_x($array) {
$array{'x'}++;
return $array;
}

$array = array();
$array['x'] = 1;

$array2 = array_inc_x($array);
array_inc_x($array2);

print $array['x'] . ', ' . $array2['x'] . "\n";

# (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);

print $array['x'] . ', ' . $array2['x'] . "\n";

bgalloway at citycarshare dot org 27-Mar-2008 06:27

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";
?>

Only myfunc5() returns 'thingy' - the rest return 1.

nick at itomic.com 04-Aug-2003 12:56


Functions which return references, may return a NULL value. This is inconsistent with the fact that
function parameters passed by reference can't be passed as NULL (or in fact anything which isnt a
variable).

i.e.

<?php

function &testRet()
{
return NULL;
}

if (testRet() === NULL)


{
echo "NULL";
}
?>

parses fine and echoes NULL


Variable functions
PHP supports the concept of variable functions. This means that if a variable name has
parentheses appended to it, PHP will look for a function with the same name as whatever
the variable evaluates to, and will attempt to execute it. Among other things, this can be
used to implement callbacks, function tables, and so forth.

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.

Example #1 Variable function example

<?php
function foo() {
echo "In foo()<br />\n";
}

function bar($arg = '')


{
echo "In bar(); argument was '$arg'.<br />\n";
}

// This is a wrapper function around echo


function echoit($string)
{
echo $string;
}

$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.

Example #2 Variable method example

<?php
class Foo
{
function Variable()
{
$name = 'Bar';
$this->$name(); // This calls the Bar() method
}

function Bar()
{
echo "This is Bar";
}
}

$foo = new Foo();


$funcname = "Variable";
$foo->$funcname(); // This calls $foo->Variable()

?>

When calling static methods, the function call is stronger than the static property operator:

Example #3 Variable method example with static properties

<?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.

?>

Example #4 Complex callables

<?php
class Foo
{
static function bar()
{
echo "bar\n";
}
function baz()
{
echo "baz\n";
}
}

$func = array("Foo", "bar");


$func(); // prints "bar"
$func = array(new Foo, "baz");
$func(); // prints "baz"
$func = "Foo::bar";
$func(); // prints "bar"
?>

See Also

 is_callable()
 call_user_func()
 function_exists()
 variable variables

User Contributed Notes


Anonymous 23-May-2020 05:26

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.

It's the same as


<?php
$choice = "func1"; // with quotes
?>

You can do echo gettype($choice) to confirm.

So calling
<?php
$choice()
?>
is a variable-function for both cases, calling it by its name, not by reference.

Go via an assigned anonymous function to get a reference to the function:


<?php
$func1 = function(){ echo "hell0 1";}
$func1 = function(){ echo "hell0 2";}
?>

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
?>

rnealxp at yahoo dot com 16-May-2020 01:17


<?php
/*
You might have found yourself at this php variable functions page because, like me, you wanted to pass
functions
around like objects to client objects as you can in JavaScript. The issue I ran into was although
I could call a function using a variable like this " $v(); "...I could not do it like this " $obj->p() "
where
'p' is a property containing the name of the method to call. Did not want to save my property off to a
variable prior
to making my call: " $v = $obj->p; $v(); "; even if one finds a way, the below applies...

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.
?>

niemans at pbsolo dot nl 19-Mar-2019 11:28

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.

const DEBUGME ='func';


function func($s) { echo $s. "\n"; }

DEBUGME('abc'); // results in a syntax error

$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:

function dynamic($what, $with)


{
$what($with);
}
dynamic(DEBUGME, 'abc');

This makes sense to me to hide API's and/or long (complicated) static calls.
Enjoy!

josh at joshstroup dot xyz 21-Apr-2016 05:58


A small, but helpful note. If you are trying to call a static function from a different namespace, you
must use the fully qualified namespace, even if they have the same top level namespace(s). For
example if you have the following class to call:

<?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();
}
}
?>

Anonymous 27-Jun-2011 11:20


$ wget http://www.php.net/get/php_manual_en.tar.gz/from/a/mirror
$ grep -l "\$\.\.\." php-chunked-xhtml/function.*.html
List of functions that accept variable arguments.
<?php
array_diff_assoc()
array_diff_key()
array_diff_uassoc()
array()
array_intersect_ukey()
array_map()
array_merge()
array_merge_recursive()
array_multisort()
array_push()
array_replace()
array_replace_recursive()
array_unshift()
call_user_func()
call_user_method()
compact()
dba_open()
dba_popen()
echo()
forward_static_call()
fprintf()
fscanf()
httprequestpool_construct()
ibase_execute()
ibase_set_event_handler()
ibase_wait_event()
isset()
list()
maxdb_stmt_bind_param()
maxdb_stmt_bind_result()
mb_convert_variables()
newt_checkbox_tree_add_item()
newt_grid_h_close_stacked()
newt_grid_h_stacked()
newt_grid_v_close_stacked()
newt_grid_v_stacked()
newt_win_choice()
newt_win_entries()
newt_win_menu()
newt_win_message()
newt_win_ternary()
pack()
printf()
register_shutdown_function()
register_tick_function()
session_register()
setlocale()
sprintf()
sscanf()
unset()
var_dump()
w32api_deftype()
w32api_init_dtype()
w32api_invoke_function()
wddx_add_vars()
wddx_serialize_vars()
?>

boards at gmail dot com 22-Jan-2006 10:07

If you want to call a static function (PHP5) in a variable method:

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');
}

static function a($name, &$value) {


echo $name,' => ',$value++,"\n";
}

function b($name, &$value) {


call_user_func_array($this->a, array($name, &$value));
}

static function c($str) {


echo $str,"\n";
}

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');
}

static function c() {


print_r(func_get_args());
}

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.
?>

Internal (built-in) functions


PHP comes standard with many functions and constructs. There are also functions that
require specific PHP extensions compiled in, otherwise fatal "undefined function" errors will
appear. For example, to use image functions such as imagecreatetruecolor(), PHP must be
compiled with GD support. Or, to use mysqli_connect(), PHP must be compiled with MySQLi
support. There are many core functions that are included in every version of PHP, such as
the string and variable functions. A call to phpinfo() or get_loaded_extensions() will show
which extensions are loaded into PHP. Also note that many extensions are enabled by default
and that the PHP manual is split up by extension. See the configuration, installation, and
individual extension chapters, for information on how to set up PHP.

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.

Anonymous functions are implemented using the Closure class.

Example #1 Anonymous function example

<?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:

Example #2 Anonymous function variable assignment example

<?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.

Example #3 Inheriting variables from the parent scope

<?php
$message = 'hello';

// No "use"
$example = function () {
var_dump($message);
};
$example();

// Inherit $message
$example = function () use ($message) {
var_dump($message);
};
$example();

// Inherited variable's value is from when the function


// is defined, not when called
$message = 'world';
$example();

// Reset message
$message = 'hello';

// Inherit by-reference
$example = function () use (&$message) {
var_dump($message);
};
$example();

// The changed value in the parent scope


// is reflected inside the function call
$message = 'world';
$example();

// Closures can also accept regular arguments


$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hello");
?>

The above example will output something similar to:

Notice: Undefined variable: message in /example.php on line 6


NULL
string(5) "hello"
string(5) "hello"
string(5) "hello"
string(5) "world"
string(11) "hello world"

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:

Example #4 Closures and scoping

<?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;

protected $products = array();

public function add($product, $quantity)


{
$this->products[$product] = $quantity;
}

public function getQuantity($product)


{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}

public function getTotal($tax)


{
$total = 0.00;

$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);
}
}

$my_cart = new Cart;

// Add some items to the cart


$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);

// Print the total with a 5% sales tax.


print $my_cart->getTotal(0.05) . "\n";
// The result is 54.29
?>

Example #5 Automatic binding of $this

<?php

class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();

?>

The above example will output:

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.

Static anonymous functions

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.

Example #6 Attempting to use $this inside a static anonymous function

<?php

class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();

?>

The above example will output:

Notice: Undefined variable: this in %s on line %d


NULL

Example #7 Attempting to bind an object to a static anonymous function

<?php

$func = static function() {


// function body
};
$func = $func->bindTo(new StdClass);
$func();
?>

The above example will output:

Warning: Cannot bind an instance to a static closure in %s on line %d


Changelog
Version Description

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.

User Contributed Notes


jake dot tunaley at berkeleyit dot com 07-Jan-2019 05:04
Beware of using $this in anonymous functions assigned to a static variable.

<?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
?>

dexen dot devries at gmail dot com 07-Jun-2018 09:54


Every instance of a lambda has own instance of static variables. This provides for great event handlers,
accumulators, etc., etc.

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

function generate_lambda() : Closure


{
# creates new instance of lambda
return function($v = null) {
static $stored;
if ($v !== null)
$stored = $v;
return $stored;
};
}

$a = generate_lambda(); # creates new instance of statics


$b = generate_lambda(); # creates new instance of statics
$c = $b; # uses the same instance of statics as $b

$a('test AAA');
$b('test BBB');
$c('test CCC'); # this overwrites content held by $b, because it refers to the same object

var_dump([ $a(), $b(), $c() ]);


?>

This test script outputs:


array(3) {
[0]=>
string(8) "test AAA"
[1]=>
string(8) "test CCC"
[2]=>
string(8) "test CCC"
}
toonitw at gmail dot com 27-Dec-2017 05:40
As of PHP 7.0, you can use IIFE(Immediately-invoked function expression) by wrapping your
anonymous function with ().

<?php
$type = 'number';
var_dump( ...( function() use ($type) {
if ($type=='number') return [1,2,3];
else if ($type=='alphabet') return ['a','b','c'];
} )() );
?>

ayon at hyurl dot com 29-Apr-2017 05:35


One way to call a anonymous function recursively is to use the USE keyword and pass a
reference to the function itself:

<?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
?>

john at binkmail dot com 07-Feb-2017 07:36


PERFORMANCE BENCHMARK 2017!

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:

a single saved closure kept in a variable and re-used (10000000 iterations):


1.3874590396881 seconds

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. :-)

erolmon dot kskn at gmail dot com 19-Jun-2015 09:48


<?php
/*
(string) $name Name of the function that you will add to class.
Usage : $Foo->add(function(){},$name);
This will add a public function in Foo Class.
*/
class Foo
{
public function add($func,$name)
{
$this->{$name} = $func;
}
public function __call($func,$arguments){
call_user_func_array($this->{$func}, $arguments);
}
}
$Foo = new Foo();
$Foo->add(function(){
echo "Hello World";
},"helloWorldFunction");
$Foo->add(function($parameterone){
echo $parameterone;
},"exampleFunction");
$Foo->helloWorldFunction(); /*Output : Hello World*/
$Foo->exampleFunction("Hello PHP"); /*Output : Hello PHP*/
?>

mail at mkharitonov dot net 20-Feb-2014 11:20


Some comparisons of PHP and JavaScript closures.

=== Example 1 (passing by value) ===


PHP code:
<?php
$aaa = 111;
$func = function() use($aaa){ print $aaa; };
$aaa = 222;
$func(); // Outputs "111"
?>

Similar JavaScript code:


< script type="text/javascript">
var aaa = 111;
var func = (function(aaa){ return function(){ alert(aaa); } })(aaa);
aaa = 222;
func(); // Outputs "111"
< /script>

Be careful, following code is not similar to previous code:


< script type="text/javascript">
var aaa = 111;
var bbb = aaa;
var func = function(){ alert(bbb); };
aaa = 222;
func(); // Outputs "111", but only while "bbb" is not changed after function declaration

// And this technique is not working in loops:


var functions = [];
for (var i = 0; i < 2; i++)
{
var i2 = i;
functions.push(function(){ alert(i2); });
}
functions[0](); // Outputs "1", wrong!
functions[1](); // Outputs "1", ok
< /script>

=== Example 2 (passing by reference) ===


PHP code:
<?php
$aaa = 111;
$func = function() use(&$aaa){ print $aaa; };
$aaa = 222;
$func(); // Outputs "222"
?>

Similar JavaScript code:


< script type="text/javascript">
var aaa = 111;
var func = function(){ alert(aaa); };
aaa = 222; // Outputs "222"
func();
< /script>

derkontrollfreak+9hy5l at gmail dot com 09-Jan-2014 04:41


Beware that since PHP 5.4 registering a Closure as an object property that has been
instantiated in the same object scope will create a circular reference which prevents
immediate object destruction:
<?php

class Test
{
private $closure;

public function __construct()


{
$this->closure = function () {
};
}

public function __destruct()


{
echo "destructed\n";
}
}

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

public function __construct()


{
$this->closure = self::createClosure();
}

public static function createClosure()


{
return function () {
};
}

?>

cHao 13-Dec-2013 11:42


In case you were wondering (cause i was), anonymous functions can return references just
like named functions can. Simply use the & the same way you would for a named
function...right after the `function` keyword (and right before the nonexistent name).

<?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)'

mike at borft dot student dot utwente dot nl 24-Jan-2012 02:46


Since it is possible to assign closures to class variables, it is a shame it is not
possible to call them directly. ie. the following does not work:
<?php
class foo {

public test;

public function __construct(){


$this->test = function($a) {
print "$a\n";
};
}
}

$f = new foo();

$f->test();
?>

However, it is possible using the magic __call function:


<?php
class foo {

public test;
public function __construct(){
$this->test = function($a) {
print "$a\n";
};
}

public function __call($method, $args){


if ( $this->{$method} instanceof Closure ) {
return call_user_func_array($this->{$method},$args);
} else {
return parent::__call($method, $args);
}
}
}
$f = new foo();
$f->test();
?>
it
Hope it helps someone ;)

simon at generalflows dot com 05-Aug-2011 08:23


<?php

/*
* 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');

?>

orls 08-Aug-2010 06:53


Watch out when 'importing' variables to a closure's scope -- it's easy to miss / forget
that they are actually being *copied* into the closure's scope, rather than just being
made available.

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); };

$two = function() use ($result)


{ var_dump($result); };

$three = function() use (&$result)


{ 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 = function() uses ($myInstance)


{
if(!empty($myInstance)) $myInstance->doSomething();
};

$working = function() uses (&$myInstance)


{
if(!empty($myInstance)) $myInstance->doSomething();
}

//$myInstance might be instantiated, might not be


if(SomeBusinessLogic::worked() == true)
{
$myInstance = new myClass();
}

$broken(); // will never do anything: $myInstance will ALWAYS be null inside this closure.
$working(); // will call doSomething if $myInstance is instantiated

?>

gabriel dot totoliciu at ddsec dot net 19-Jul-2010 10:56


If you want to make a recursive closure, you will need to write this:

$some_var1="1";
$some_var2="2";

function($param1, $param2) use ($some_var1, $some_var2)


{

//some code here

call_user_func(__FUNCTION__, $other_param1, $other_param2);

//some code here

If you need to pass values by reference you should check out

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.

kdelux at gmail dot com 14-May-2010 08:55


Here is an example of one way to define, then use the variable ( $this ) in Closure
functions. The code below explores all uses, and shows restrictions.

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'))

Failure: reference anything through $this->


Failure: $this->name = '';
Failure: $this->delfect();

<?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;

function __invoke($p){ return $this->$p; }


function __toString(){ return 'this'; } // test for reference

function __construct($name){ $this->name = $name; }


function deflect(){ $this->deflected = true; }

public function shoot()


{ // If customAttack is defined, use that as the shoot resut. Otherwise shoot feet
if(is_callable($this->customAttack)){
return call_user_func($this->customAttack);
}

$this->feet = false;
}
}
$p = new Person('Bob');

$p->customAttack =
function(){

echo $this; // Notice: Undefined variable: this

#$this = new Class() // FATAL ERROR

// Trick to assign the variable '$this'


extract(array('this' => requesting_class())); // Determine what class is responsible
for making the call to Closure

var_dump( $this ); // Passive reference works


var_dump( $$this ); // Added to class: function __toString(){ return 'this'; }

$name = $this('name'); // Success


echo $name; // Outputs: Bob
echo '<br />';
echo $$this->name;

call_user_func_array(array($this, 'deflect'), array()); // SUCCESSFULLY CALLED

#$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();

?>

rob at ubrio dot us 25-Nov-2009 10:20


You can always call protected members using the __call() method - similar to how you hack
around this in Ruby using send.

<?php

class Fun
{
protected function debug($message)
{
echo "DEBUG: $message\n";
}

public function yield_something($callback)


{
return $callback("Soemthing!!");
}
public function having_fun()
{
$self =& $this;
return $this->yield_something(function($data) use (&$self)
{
$self->debug("Doing stuff to the data");
// do something with $data
$self->debug("Finished doing stuff with the data.");
});
}

// Ah-Ha!
public function __call($method, $args = array())
{
if(is_callable(array($this, $method)))
return call_user_func_array(array($this, $method), $args);
}
}

$fun = new Fun();


echo $fun->having_fun();

?>

Anonymous 03-Aug-2009 02:50


If you want to check whether you're dealing with a closure specifically and not a string
or array callback you can do this:

<?php
$isAClosure = is_callable($thing) && is_object($thing);
?>

a dot schaffhirt at sedna-soft dot de 19-Jun-2009 02:55


When using anonymous functions as properties in Classes, note that there are three name
scopes: one for constants, one for properties and one for methods. That means, you can
use the same name for a constant, for a property and for a method at a time.

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.

Consider the following example:

<?php
class MyClass {
const member = 1;

public $member;

public function member () {


return "method 'member'";
}

public function __construct () {


$this->member = function () {
return "anonymous function 'member'";
};
}
}

header("Content-Type: text/plain");

$myObj = new MyClass();

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 have the basic form fn (argument_list) => expr.

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.

Example #1 Arrow functions capture variables by value automatically

<?php

$y = 1;

$fn1 = fn($x) => $x + $y;


// equivalent to using $y by value:
$fn2 = function ($x) use ($y) {
return $x + $y;
};

var_export($fn1(3));
?>

The above example will output:


4

This also works if the arrow functions are nested:

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:

Example #3 Examples of arrow functions

<?php

fn(array $x) => $x;


static fn(): int => $x;
fn($x = 42) => $x;
fn(&$x) => $x;
fn&($x) => $x;
fn($x, ...$rest) => $rest;

?>

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

7.4.0 Arrow functions became available.

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)
}

Koushil Mankali 27-Jul-2020 06:58


In 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

?>

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);

?>

Output : 2 (as expected)

But here it will not take values from parent scope automatically but we have to pass them
explicitly.

You might also like