13 函数
概述
When a function is called, information may be passed to it by the caller via an argument list, which contains one or more argument expressions, or more simply, arguments. These correspond by position to the parameters in a parameter list in the called function's definition.
An unconditionally defined function is a function whose definition is at the top level of a script. A conditionally defined function is a function whose definition occurs inside a compound statement, such as the body of another function (a nested function), conditional statement, etc. There is no limit on the depth of levels of function nesting. Consider the case of an outer function, and an inner function defined within it. Until the outer function is called at least once, its inner function does not exist. Even if the outer function is called, if its runtime logic bypasses the definition of the inner function, that inner function still does not exist. The conditionally defined function comes into existance when the execution flow reaches the point where the function is defined.
Any function containing yield
is a generator function.
Examples
ucf1(); // can call ucf1 before its definition is seen
function ucf1() { ... }
ucf1(); // can call ucf1 after its definition is seen
cf1(); // Error; call to non-existent function
$flag = TRUE;
if ($flag) { function cf1() { ... } } // cf1 now exists
if ($flag) { cf1(); } // can call cf1 now
// -----------------------------------------
function ucf2() { function cf2() { ... } }
cf2(); // Error; call to non-existent function
ucf2(); // now cf2 exists
cf2(); // so we can call it
Function Calls
A function is called via the function-call operator ()
.
Function Definitions
Syntax
function-definition: function-definition-header compound-statement function-definition-header: function &opt name ( parameter-declaration-listopt ) return-typeopt parameter-declaration-list: simple-parameter-declaration-list variadic-declaration-list simple-parameter-declaration-list: parameter-declaration parameter-declaration-list , parameter-declaration variadic-declaration-list: simple-parameter-declaration-list , variadic-parameter variadic-parameter parameter-declaration: type-declarationopt &opt variable-name default-argument-specifieropt variadic-parameter: type-declarationopt &opt ... variable-name return-type: : type-declaration : void type-declaration: array callable iterable scalar-type qualified-name scalar-type: bool float int string default-argument-specifier: = constant-expression
Constraints
Each parameter name in a function-definition must be distinct.
A conditionally defined function must exist before any calls are made to that function.
The function-definition for constructors, destructors, and clone methods must not contain return-type.
For generator functions, if the the return type is specified, it can only be one of: Generator
, Iterator
or Traversable
.
Semantics
A function-definition defines a function called name. Function names are not case-sensitive. A function can be defined with zero or more parameters, each of which is specified in its own parameter-declaration in a parameter-declaration-list. Each parameter has a name, variable-name, and optionally, a default-argument-specifier. An &
in parameter-declaration indicates that parameter is passed byRef rather than by value. An &
before name indicates that the value returned from this function is to be returned byRef. Returning values is described in return
statement description.
When the function is called, if there exists a parameter for which there is a corresponding argument, the argument is assigned to the parameter variable using value assignment, while for passing byRef, the argument is assigned to the parameter variable using byRef assignment. If that parameter has no corresponding argument, but the parameter has a default argument value, for passing by value or byRef, the default value is assigned to the parameter variable using value assignment. Otherwise, if the parameter has no corresponding argument and the parameter does not have a default value, the parameter variable is non-existent and no corresponding VSlot exists. After all possible parameters have been assigned initial values or aliased to arguments, the body of the function, compound-statement, is executed. This execution may terminate normally, with return
statement or abnormally.
Each parameter is a variable local to the parent function, and is a modifiable lvalue.
A function-definition may exist at the top level of a script, inside any compound-statement, in which case, the function is conditionally defined, or inside a method-declaration section of a class.
If variadic-parameter is defined, every parameter that is supplied to function and is not matched by the preceding parameters is stored in this parameter, as an array element. The first such parameter gets index 0, the next one 1, etc. If no extra parameters is supplied, the value of the parameter is an empty array. Note that if type and/or byRef specifications are supplied to variadic parameter, they apply to every extra parameter captured by it.
By default, a parameter will accept an argument of any type. However, by specifying a type-declaration, the types of argument accepted can be restricted. By specifying array
, only an argument of the array
type is accepted. By specifying callable
, only an argument designating a function (see below) is accepted. By specifying iterable
, only an argument that is of type array
or an object implementing the Traversable
interface is accepted. By specifying qualified-name, only an instance of a class having that type, or being derived from that type, are accepted, or only an instance of a class that implements that interface type directly or indirectly is accepted. The check is the same as for instanceof
operator.
callable
pseudo-type accepts the following:
- A string value containing the name of a function defined at the moment of the call.
- An array value having two elements under indexes
0
and1
. First element can be either string or object. If the first element is a string, the second element must be a string naming a method in a class designated by the first element. If the first element is an object, the second element must be a string naming a method that can be called on an object designated by the first element, from the context of the function being called. - An instance of the
Closure
class. - An instance of a class implementing
__invoke
.
The library function is_callable
reports whether the contents of a variable can be called as a function.
Parameters typed with scalar-type are accepted if they pass the type check for this scalar type, as described below. Once the checks have been passed, the parameter types are always of the scalar type specified (or NULL
if NULL
is allowed).
If a parameter has a type declaration, NULL
is not accepted unless it has a default value that evaluates to NULL
.
The default value for a typed parameter must be of the type specified, or NULL
, and conversion is not be performed for defaults, regardless of the mode.
Return typing
If the function is defined with return-type declaration, the value returned by the function should be compatible with the defined type, using the same rules as for parameter type checks. NULL
values are not allowed for typed returns. If the value of the return
statement does not pass the type check, a fatal error is produced.
The void
type is a special type that can only be used as a return type, and not in other contexts. It has no effect at runtime, see the return
statement.
Type check modes
The type checking can be performed in two modes, strict and coercive (default). The difference between modes exists only for scalar typed parameters (int
, float
, string
and bool
).
For coercive mode, if the value passed is of the same type as the parameter, it is accepted. If not, the conversion is attempted. If the conversion succeeds, the converted value is the value assigned to the parameter. If the conversion fails, a fatal error is produced.
For strict mode, the parameter must be exactly of the type that is declared (e.g., string "1"
is not accepted as a value for parameter typed as int
). The only exception is that int
values will be accepted for float
typed parameter and converted to float
. Note that the strict mode applies not only to user-defined but also to internal functions, please consult the manual for appropriate parameter types. If the types do not match, an exception of type TypeError
is thrown.
Note that if the parameter is passed byRef, and conversion happened, then the value will be re-assigned with the newly converted value.
The mode is set by the declare
statement.
Note that the type check mode is for the function call controleed by the caller, not the callee. While the check is performed in the function being called, the caller defines whether the check is strict. Same function can be called with both strict and coercive mode checks from different contexts.
The check for the return type is always defined by the script that the function was defined in.
Examples
// coercive mode by default
function accept_int(int $a) { return $a+1; }
accept_int(1); // ok
accept_int("123"); // ok
accept_int("123.34"); // ok
accept_int("123.34 and some"); // ok + notice
accept_int("not 123"); // fatal error!
accept_int(null); // fatal error
function accept_int_or_not(int $a = null) { return $a+1; }
accept_int_or_not(null); // ok
function convert_int(int &$a) { return $a+1; }
$a = "12";
convert_int($a);
var_dump($a); // $a is now int
// Now in strict mode
declare(strict_types=1);
function accept_int(int $a) { return $a+1; }
function accept_float(float $a) { return $a+1; }
accept_int(1); // ok
accept_float(1); // ok
accept_int(1.5); // fatal error
accept_int("123"); // fatal error
echo substr("123", "1"); // fatal error
Variable Functions
If a variable name is followed by the function-call operator ()
, and the value of that variable designates the function currently defined and visible (see description above), that function will be executed. If the variable does not designate a function or this function can not be called, a fatal error is produced.
Anonymous Functions
An anonymous function, also known as a closure, is a function defined with no name. As such, it must be defined in the context of an expression whose value is used immediately to call that function, or that is saved in a variable for later execution. An anonymous function is defined via the anonymous function creation operator.
For both __FUNCTION__
and __METHOD__
, an anonymous function's name is reported as {closure}
.