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:

Note:
As of PHP 5, arguments that are passed by reference may have a default value.

Type declarations

Note:

Type declarations were also known as type hints in PHP 5.

Type declarations allow functions to require that parameters are of a certain type at call time.
If the given value is of the incorrect type,
then an error is generated: in PHP 5, this will be a recoverable fatal
error, while PHP 7 will throw a TypeError
exception.

To specify a type declaration, the type name should be added before the
parameter name. The declaration can be made to accept NULL values if
the default value of the parameter is set to NULL.

Valid types

Type

Description

Minimum PHP version

Class/interface name

The parameter must be an instanceof the given class or interface
name.

PHP 5.0.0

self

The parameter must be an instanceof the same class as the one the
method is defined on. This can only be used on class and instance
methods.

Aliases for the above scalar types are not supported. Instead, they are
treated as class or interface names. For example, using
boolean as a parameter or return type will require
an argument or return value that is an instanceof the class or
interface boolean, rather than of type
bool:

<?phpfunction test(boolean $param) {}test(true);?>

The above example will output:

Fatal error: Uncaught TypeError: Argument 1 passed to test() must be an instance of boolean, boolean given, called in - on line 1 and defined in -:1

Examples

Example #7 Basic class type declaration

<?phpclass C {}class D extends C {}

// This doesn't extend C.class E {}

function f(C $c) { echo get_class($c)."\n";}

f(new C);f(new D);f(new E);?>

The above example will output:

C
D
Fatal error: Uncaught TypeError: Argument 1 passed to f() must be an instance of C, instance of E given, called in - on line 14 and defined in -:8
Stack trace:
#0 -(14): f(Object(E))
#1 {main}
thrown in - on line 8

Strict typing

By default, PHP will coerce values of the wrong type into the expected
scalar type if possible. For example, a function that is given an
integer for a parameter that expects a string
will get a variable of type string.

It is possible to enable strict mode on a per-file basis. In strict
mode, only a variable of exact type of the type declaration will be
accepted, or a TypeError will be thrown. The
only exception to this rule is that an integer may be given
to a function expecting a float. Function calls from within
internal functions will not be affected by the strict_types
declaration.

To enable strict mode, the declare statement is used with the
strict_types declaration:

Strict typing applies to function calls made from
within the file with strict typing enabled, not to
the functions declared within that file. If a file without strict
typing enabled makes a call to a function that was defined in a file
with strict typing, the caller's preference (weak typing) will be
respected, and the value will be coerced.

Note:

Strict typing is only defined for scalar type declarations, and as
such, requires PHP 7.0.0 or later, as scalar type declarations were
added in that version.

Example #10 Strict typing

<?phpdeclare(strict_types=1);

function sum(int $a, int $b) { return $a + $b;}

var_dump(sum(1, 2));var_dump(sum(1.5, 2.5));?>

The above example will output:

int(3)
Fatal error: Uncaught TypeError: Argument 1 passed to sum() must be of the type integer, float given, called in - on line 9 and defined in -:4
Stack trace:
#0 -(9): sum(1.5, 2.5)
#1 {main}
thrown in - on line 4

Example #11 Weak typing

<?phpfunction sum(int $a, int $b) { return $a + $b;}

var_dump(sum(1, 2));

// These will be coerced to integers: note the output below!var_dump(sum(1.5, 2.5));?>

int(3)
Error: Argument 1 passed to sum() must be of the type integer, float given, called in - on line 10

Variable-length argument lists

PHP has support for variable-length argument lists in
user-defined functions. This is implemented using the
... token in PHP 5.6 and later, and using the
func_num_args(),
func_get_arg(), and
func_get_args() functions in PHP 5.5 and earlier.

... in PHP 5.6+

In PHP 5.6 and later, 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:

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".*/?>

You can use (very) limited signatures for your functions, specifing type of arguments allowed.

For example:

public function Right( My_Class $a, array $b )

tells first argument have to by object of My_Class, second an array. My_Class means that you can pass also object of class that either extends My_Class or implements (if My_Class is abstract class) My_Class. If you need exactly My_Class you need to either make it final, or add some code to check what $a really.

Also note, that (unfortunately) "array" is the only built-in type you can use in signature. Any other types i.e.:

public function Wrong( string $a, boolean $b )

will cause an error, because PHP will complain that $a is not an *object* of class string (and $b is not an object of class boolean).

So if you need to know if $a is a string or $b bool, you need to write some code in your function body and i.e. throw exception if you detect type mismatch (or you can try to cast if it's doable).

PASSING A "VARIABLE-LENGTH ARGUMENT LIST OF REFERENCES" TO A FUNCTIONAs 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.

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

// Outputs "Hello World!":myFunction("Hello World!");// Outputs "Using a variable as a default value!":myFunction();// Outputs the same again:myFunction(null);// Outputs "Changing the variable affects the function!":$myVar = "Changing the variable affects the function!";myFunction();?>In general, you define the default value as null (or whatever constant you like), and then check for that value at the start of the function, computing the actual default if needed, before using the argument for actual work.Building upon this, it's also easy to provide fallback behaviors when the argument given is not valid: simply put a default that is known to be invalid in the prototype, and then check for general validity instead of a specific value: if the argument is not valid (either not given, so the default is used, or an invalid value was given), the function computes a (valid) default to use.

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:

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.

by default Classes constructor does not have any arguments. Using small trick with func_get_args() and other relative functions constructor becomes a function w/ args (tested in php 5.1.2). Check it out:

Nothing was written here about argument types as part of the function definition.

When working with classes, the class name can be used as argument type. This acts as a reminder to the user of the class, as well as a prototype for php control. (At least in php 5 -- did not check 4).

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.

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

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

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.

Usage of "?" Is also possible with "string", "int", "array" and so on primitive types (which is strange). Also unliKe "= null" "?" can be passed not only for tail of arguments, e.g.:<?phpfunction foo(?string $a, string $b) {}?>

I started to learn for the Zend Certificate exam a few days ago and I got stuck with one unanswered-well question.
This is the question:
“Absent any actual need for choosing one method over the other, does passing arrays by value to a read-only function reduce performance compared to passing them by reference?’

This question answered by Zend support team at Zend.com:

"A copy of the original $array is created within the function scope. Once the function terminates, the scope is removed and the copy of $array with it." (By massimilianoc)

Call-time pass-by-ref arguments are deprecated and may not be supported later, so doing this:

----function foo($str) { $str = "bar";}

$mystr = "hello world";foo(&$mystr);----

will produce a warning when using the recommended php.ini file. The way I ended up using for optional pass-by-ref args is to just pass an unused variable when you don't want to use the resulting parameter value:

some_function(); //this will behave as expected, displaying 'value1, value2, value3'some_function(null,null,null); //this on the other hand will display ', ,' since the variables will take the null value.?>

I came to about the same conclusion as jcaplan. To force your function parameters to take a default value when a null is passed you need to include a conditionnal assignment inside the function definition.

<?phpfunction some_function($v1='value1',$v2='value1',$v3=null){$v1=(is_null($v1)?'value1':$v1);$v2=(is_null($v2)?'value2':$v2);$v3=(is_null($v3)?'value3':$v3); echo $v1; echo $v2; echo $v3;}/* The default value whether null or an actual value is not so important in the parameter list, what is important is that you include it to allow a default behavior. The default value in the declaration becomes more important at this point:*/?>

Be careful when passing arguments by reference, it can cause unexpected side-effects if one is not careful.

I had a program designed to sweep through directories and subdirectories and report on the total number of files, and the total size of all files. Since it needed to return two values, I used variables passed by reference.

In one spot in the program, I didn't need the values of those variables after they were returned, so I just used a garbage variable named $ignore instead. This caused a curious bug which took me a while to track down, because the effects of the bug were in a different part of the program than the place where I had made a mistake.

Since the same variable was used for both parameters passed by reference, they ended up both pointing to the same physical location in memory, so changing one of them caused both of them to change. The code below is an excerpt of my program, stripped down to just the few lines necessary to illustrate what was happening:

It is so easy to create a constant that the php novice might do so accidently while attempting to call a function with no arguments. For example:<?phpfunction LogoutUser(){// destroy the session, the cookie, and the session IDblah blah blah; return true;}function SessionCheck(){blah blah blah;// check for session timeout... if ($timeout) LogoutUser; // should be LogoutUser();}?>

OOPS! I don't notice my typo, the SessionCheck functiondoesn't work, and it takes me all afternoon to figure out why not!

I personally wouldn't recommend (B) - I think it strange why php would support such a convention as it would have violated foo_b's design - its use would not do justice to its function prototype. And thinking about such use, I might have to think about copying all variables instead of working directly on them...

Coding that respects function prototypes strictly would, I believe, result in code that is more intuitive to read. Of course, in php <=4, not being able to use default values with references, we can't do this that we can do in C:

(in reply to benk at NOSPAM dot icarz dot com / 24-Jun-2005 04:21)I could make use of this assignment, as below, to have a permanently existing, but changing data block (because it is used by many other classes), where the order or the refreshed contents are needed for the others: (DB init done by one, an other changed the DB, and thereafter all others need to use the other DB without creating new instances, or creating a log array in one, and we would like to append the new debug strings to the array, atmany places.)

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

There seems to be one exception to this. Say you're using type-hinting for an argument, but you want to allow it to be NULL, and you want additional required arguments to the right of it. PHP allows this, as long as you give it the type-hinted argument a default value of NULL. For example:

I have some functions that I'd like to be able to pass arguments two ways: Either as an argument list of variable length (e.g. func(1, 2, 3, 4)) or as an array (e.g., func(array(1,2,3,4)). Only the latter can be constructed on the fly (e.g., func($ar)), but the syntax of the former can be neater.

The way to do it is to begin the function as follows: $args = func_get_args(); if (is_array ($args[0])) $args = $args[0];Then one can just use $args as the list of arguments.