Callable 可调用 回调函数 一级可调用语法

PHP: Callable - Manual

 

Callable

callable 是对函数或方法的引用,作为参数传递给其他函数,使用 callable 类型声明来表示。

<?php
function foo(callable $callback) {
    $callback();
}
?>

一些函数接受回调函数作为参数,例如 array_map()usort()preg_replace_callback()

callable 的创建

callable 是一种表示可调用内容的类型。Callable 可作为参数传递给需要回调参数的函数或方法,也可直接调用。callable 类型不能用于类属性的类型声明,此时应使用 Closure 类型声明。

Callable 可通过多种方式创建:

Closure 对象可通过匿名函数语法、箭头函数语法、一级可调用语法,或 Closure::fromCallable() 方法创建。

注意:

一级可调用语法 仅自 PHP 8.1.0 起可用。

示例 #1 使用 Closure 的 Callback 示例

<?php
// 使用匿名函数语法
$double1 = function ($a) {
    return $a * 2;
};

// 使用一级可调用语法
function double_function($a) {
    return $a * 2;
}
$double2 = double_function(...);

// 使用箭头函数语法
$double3 = fn($a) => $a * 2;

// 使用 Closure::fromCallable
$double4 = Closure::fromCallable('double_function');

// 此处使用 closure 作为回调,将范围内每个元素的值翻倍。
$new_numbers = array_map($double1, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double2, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double3, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double4, range(1, 5));
print implode(' ', $new_numbers);

?>

以上示例在 PHP 8.1 中的输出:

2 4 6 8 10
2 4 6 8 10
2 4 6 8 10
2 4 6 8 10

callable 也可以是包含函数名或静态方法名的字符串。除语言结构(如 array()echoempty()eval()isset()list()printunset())外,任何内置或用户自定义函数均可使用。

静态类方法可在不实例化该类 object 的情况下使用,方式包括:创建数组,其中索引 0 为类名,索引 1 为方法名;或使用作用域解析运算符 :: 的特殊语法,例如 'ClassName::methodName'

已实例化 object 的方法在以数组形式提供时可作为 callable,其中索引 0 为该 object,索引 1 为方法名。

Closure 对象与 callable 类型的主要区别在于,Closure 对象与作用域无关,始终可直接调用,而 callable 类型可能依赖于作用域,不一定能直接调用。创建 callable 时,推荐使用 Closure

注意:

Closure 对象绑定于其创建时所在的作用域,而以字符串或数组形式引用类方法的 callable 则在其被调用的作用域中解析。若需从 private 或 protected 方法创建可在类作用域外部调用的可调用项,应使用 Closure::fromCallable()一级可调用语法

PHP 允许创建 callable,可用作回调参数,但无法直接调用。它们是上下文相关的 callable,引用类继承层次中的某个类方法,例如 'parent::method'["static", "method"]

注意:

自 PHP 8.2.0 起,已弃用上下文相关的 callable 。应通过将 'parent::method' 替换为 parent::class . '::method',或使用一级可调用语法,以消除上下文依赖。

示例 #2 使用 call_user_function() 调用各类 callable

<?php

// callback 函数示例
function my_callback_function() {
    echo 'hello world!', PHP_EOL;
}

// callback 方法示例
class MyClass {
    static function myCallbackMethod() {
        echo 'Hello World!', PHP_EOL;
    }
}

// 类型 1:简单回调
call_user_func('my_callback_function');

// 类型2:静态类方法回调
call_user_func(['MyClass', 'myCallbackMethod']);

// 类型 3:对象方法回调
$obj = new MyClass();
call_user_func([$obj, 'myCallbackMethod']);

// 类型 4:静态类方法回调
call_user_func('MyClass::myCallbackMethod');

// 类型 5:使用 ::class 关键字的静态类方法回调
call_user_func([MyClass::class, 'myCallbackMethod']);

// 类型 6:相对静态类方法调用
class A {
    public static function who() {
        echo 'A', PHP_EOL;
    }
}

class B extends A {
    public static function who() {
        echo 'B', PHP_EOL;
    }
}

call_user_func(['B', 'parent::who']); // 自 PHP 8.2.0 起弃用

// 类型 7:实现 __invoke 的对象用于 callable
class C {
    public function __invoke($name) {
        echo 'Hello ', $name;
    }
}

$c = new C();
call_user_func($c, 'PHP!');
?>

以上示例会输出:

hello world!
Hello World!
Hello World!
Hello World!
Hello World!

Deprecated: Callables of the form ["B", "parent::who"] are deprecated in script on line 41
A
Hello PHP!

注意:

在函数中注册有多个回调内容时(如使用 call_user_func()call_user_func_array()),如在前一个回调中有未捕获的异常,其后的将不再被调用。

 

 

Callables

A callable is a reference to a function or method that is passed to another function as an argument. They are represented with the callable type declaration.

<?php
function foo(callable $callback) {
    $callback();
}
?>

Some functions accept callback functions as a parameter, e.g. array_map(), usort(), or preg_replace_callback().

Creation of callables

A callable is a type that represents something that can be invoked. Callables can be passed as arguments to functions or methods which expect a callback parameter or they can be invoked directly. The callable type cannot be used as a type declaration for class properties. Instead, use a Closure type declaration.

Callables can be created in several different ways:

  • Closure object

  • string containing the name of a function or a method

  • array containing a class name or an object in index 0 and the method name in index 1

  • object implementing the __invoke() magic method

A Closure object can be created using anonymous function syntax, arrow function syntax, first-class callable syntax, or the Closure::fromCallable() method.

Note:

The first-class callable syntax is only available as of PHP 8.1.0.

Example #1 Callback example using a Closure

<?php
// Using anonymous function syntax
$double1 = function ($a) {
    return $a * 2;
};

// Using first-class callable syntax
function double_function($a) {
    return $a * 2;
}
$double2 = double_function(...);

// Using arrow function syntax
$double3 = fn($a) => $a * 2;

// Using Closure::fromCallable
$double4 = Closure::fromCallable('double_function');

// Use the closure as a callback here to
// double the size of each element in our range
$new_numbers = array_map($double1, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double2, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double3, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double4, range(1, 5));
print implode(' ', $new_numbers);

?>

Output of the above example in PHP 8.1:

2 4 6 8 10
2 4 6 8 10
2 4 6 8 10
2 4 6 8 10

A callable can also be a string containing the name of a function or a static method. Any built-in or user-defined function can be used, except language constructs such as: array(), echo, empty(), eval(), isset(), list(), print or unset().

Static class methods can be used without instantiating an object of that class by either creating an array with the class name at index 0 and the method name at index 1, or by using the special syntax with the scope resolution operator ::, as in 'ClassName::methodName'.

A method of an instantiated object can be a callable when provided as an array with the object at index 0 and the method name at index 1.

The main difference between a Closure object and the callable type is that a Closure object is scope-independent and can always be invoked, whereas a callable type may be scope-dependent and may not be directly invoked. Closure is the preferred way to create callables.

Note:

While Closure objects are bound to the scope where they are created, callables referencing class methods as strings or arrays are resolved in the scope where they are called. To create a callable from a private or protected method, which can then be invoked from outside the class scope, use Closure::fromCallable() or the first-class callable syntax.

PHP allows the creation of callables which can be used as a callback argument but cannot be called directly. These are context-dependent callables which reference a class method in the inheritance hierarchy of a class, e.g. 'parent::method' or ["static", "method"].

Note:

As of PHP 8.2.0, context-dependent callables are deprecated. Remove the context dependency by replacing 'parent::method' with parent::class . '::method' or use the first-class callable syntax.

Example #2 Calling various types of callables with call_user_func()

<?php

// An example callback function
function my_callback_function() {
    echo 'hello world!', PHP_EOL;
}

// An example callback method
class MyClass {
    static function myCallbackMethod() {
        echo 'Hello World!', PHP_EOL;
    }
}

// Type 1: Simple callback
call_user_func('my_callback_function');

// Type 2: Static class method call
call_user_func(['MyClass', 'myCallbackMethod']);

// Type 3: Object method call
$obj = new MyClass();
call_user_func([$obj, 'myCallbackMethod']);

// Type 4: Static class method call
call_user_func('MyClass::myCallbackMethod');

// Type 5: Static class method call using ::class keyword
call_user_func([MyClass::class, 'myCallbackMethod']);

// Type 6: Relative static class method call
class A {
    public static function who() {
        echo 'A', PHP_EOL;
    }
}

class B extends A {
    public static function who() {
        echo 'B', PHP_EOL;
    }
}

call_user_func(['B', 'parent::who']); // deprecated as of PHP 8.2.0

// Type 7: Objects implementing __invoke can be used as callables
class C {
    public function __invoke($name) {
        echo 'Hello ', $name;
    }
}

$c = new C();
call_user_func($c, 'PHP!');
?>

The above example will output:

hello world!
Hello World!
Hello World!
Hello World!
Hello World!

Deprecated: Callables of the form ["B", "parent::who"] are deprecated in script on line 44
A
Hello PHP!

Note:

Callbacks registered with functions such as call_user_func() and call_user_func_array() will not be called if there is an uncaught exception thrown in a previous callback.

First class callable syntax

The first class callable syntax is introduced as of PHP 8.1.0, as a way of creating anonymous functions from callable. It supersedes existing callable syntax using strings and arrays. The advantage of this syntax is that it is accessible to static analysis, and uses the scope at the point where the callable is acquired.

CallableExpr(...) syntax is used to create a Closure object from callable. CallableExpr accepts any expression that can be directly called in the PHP grammar:

Example #1 Simple first class callable syntax

<?php
class Foo {
   public function method() {}
   public static function staticmethod() {}
   public function __invoke() {}
}

$obj = new Foo();
$classStr = 'Foo';
$methodStr = 'method';
$staticmethodStr = 'staticmethod';


$f1 = strlen(...);
$f2 = $obj(...);  // invokable object
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);

// traditional callable using string, array
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);

Note:

The ... is part of the syntax, and not an omission.

CallableExpr(...) has the same semantics as Closure::fromCallable(). That is, unlike callable using strings and arrays, CallableExpr(...) respects the scope at the point where it is created:

Example #2 Scope comparison of CallableExpr(...) and traditional callable

<?php
class Foo {
    public function getPrivateMethod() {
        return [$this, 'privateMethod'];
    }

    private function privateMethod() {
        echo __METHOD__, "\n";
    }
}

$foo = new Foo;
$privateMethod = $foo->getPrivateMethod();
$privateMethod();
// Fatal error: Call to private method Foo::privateMethod() from global scope
// This is because call is performed outside from Foo and visibility will be checked from this point.
<?php
class Foo1 {
    public function getPrivateMethod() {
        // Uses the scope where the callable is acquired.
        return $this->privateMethod(...); // identical to Closure::fromCallable([$this, 'privateMethod']);
    }

    private function privateMethod() {
        echo __METHOD__, "\n";
    }
}

$foo1 = new Foo1;
$privateMethod = $foo1->getPrivateMethod();
$privateMethod();  // Foo1::privateMethod

Note:

Object creation by this syntax (e.g new Foo(...)) is not supported, because new Foo() syntax is not considered a call.

Note:

The first-class callable syntax cannot be combined with the nullsafe operator. Both of the following result in a compile-time error:

<?php
$obj?->method(...);
$obj?->prop->method(...);

 

PHP: array_map - Manual

array_map

(PHP 4 >= 4.0.6, PHP 5, PHP 7, PHP 8)

array_map — 为数组的每个元素应用回调函数

说明

function array_map(?callable $callback, array $array, array ...$arrays): array

array_map() 返回一个 array,包含将 array 的相应值作为回调的参数顺序调用 callback 后的结果(如果提供了更多数组,还会利用 arrays 传入)。callback 函数形参的数量必须匹配 array_map() 实参中数组的数量。多余的实参数组将会被忽略。如果提供的实参数组的数量不足,将抛出 ArgumentCountError

参数

callback

回调函数 callable,应用到每个数组里的每个元素。

多个数组操作合并时,callback 可以设置为 null,并且会返回数组,该数组的每个元素包含输入数组中内部数组指针相同位置的元素(见下面的示例)。如果只提供了 array 数组,array_map() 会返回输入的数组。

array

数组,遍历运行 callback 函数。

arrays

额外的数组列表,每个都遍历运行 callback 函数。

返回值

返回数组,包含将 array 的相应值作为回调的参数调用 callback 函数后的结果(如果提供了更多数组,还会利用 arrays 传入)。

当仅仅传入一个数组时,返回的数组会保留传入参数的键(key)。 传入多个数组时,返回的数组键是按顺序的 integer。

更新日志

版本说明
8.0.0 如果 callback 接受引用传递参数,该方法将会抛出 E_WARNING

array_map

(PHP 4 >= 4.0.6, PHP 5, PHP 7, PHP 8)

array_map — Applies the callback to the elements of the given arrays

Description

function array_map(?callable $callback, array $array, array ...$arrays): array

array_map() returns an array containing the results of applying the callback to the corresponding value of array (and arrays if more arrays are provided) used as arguments for the callback. The number of parameters that the callback function accepts should match the number of arrays passed to array_map(). Excess input arrays are ignored. An ArgumentCountError is thrown if an insufficient number of arguments is provided.

Parameters

callback

A callable to run for each element in each array.

null can be passed as a value to callback to perform a zip operation on multiple arrays and return an array where each element is an array containing the elements from the input arrays at the same position of the internal array pointer (see example below). If only array is provided, array_map() will return the input array.

array

An array to run through the callback function.

arrays

Supplementary variable list of array arguments to run through the callback function.

Return Values

Returns an array containing the results of applying the callback function to the corresponding value of array (and arrays if more arrays are provided) used as arguments for the callback.

The returned array will preserve the keys of the array argument if and only if exactly one array is passed. If more than one array is passed, the returned array will have sequential integer keys.

Changelog

VersionDescription
8.0.0 If callback expects a parameter to be passed by reference, this function will now emit an E_WARNING.

 

 

PHP: call_user_func - Manual

 

PHP: 一级可调用语法 - Manual

 

 

 

python - What is a "callable"? - Stack Overflow https://stackoverflow.com/questions/111234/what-is-a-callable

 

A callable is anything that can be called.

The built-in callable (PyCallable_Check in objects.c) checks if the argument is either:

  • an instance of a class with a __call__ method or
  • is of a type that has a non null tp_call (c struct) member which indicates callability otherwise (such as in functions, methods etc.)

The method named __call__ is (according to the documentation)

Called when the instance is ''called'' as a function

Example

class Foo:
  def __call__(self):
    print 'called'

foo_instance = Foo()
foo_instance() #this is calling the __call__ method

 

 

 

From Python's sources object.c:

/* Test whether an object can be called */

int
PyCallable_Check(PyObject *x)
{
    if (x == NULL)
        return 0;
    if (PyInstance_Check(x)) {
        PyObject *call = PyObject_GetAttrString(x, "__call__");
        if (call == NULL) {
            PyErr_Clear();
            return 0;
        }
        /* Could test recursively but don't, for fear of endless
           recursion if some joker sets self.__call__ = self */
        Py_DECREF(call);
        return 1;
    }
    else {
        return x->ob_type->tp_call != NULL;
    }
}

It says:

  1. If an object is an instance of some class then it is callable iff it has __call__ attribute.
  2. Else the object x is callable iff x->ob_type->tp_call != NULL

Desciption of tp_call field:

ternaryfunc tp_call An optional pointer to a function that implements calling the object. This should be NULL if the object is not callable. The signature is the same as for PyObject_Call(). This field is inherited by subtypes.

You can always use built-in callable function to determine whether given object is callable or not; or better yet just call it and catch TypeError later. callable is removed in Python 3.0 and 3.1, use callable = lambda o: hasattr(o, '__call__') or isinstance(o, collections.Callable).

Example, a simplistic cache implementation:

class Cached:
    def __init__(self, function):
        self.function = function
        self.cache = {}

    def __call__(self, *args):
        try: return self.cache[args]
        except KeyError:
            ret = self.cache[args] = self.function(*args)
            return ret    

Usage:

@Cached
def ack(x, y):
    return ack(x-1, ack(x, y-1)) if x*y else (x + y + 1) 

Example from standard library, file site.py, definition of built-in exit() and quit() functions:

class Quitter(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'Use %s() or %s to exit' % (self.name, eof)
    def __call__(self, code=None):
        # Shells like IDLE catch the SystemExit, but listen when their
        # stdin wrapper is closed.
        try:
            sys.stdin.close()
        except:
            pass
        raise SystemExit(code)
__builtin__.quit = Quitter('quit')
__builtin__.exit = Quitter('exit')

 

 

3.3.6. 模拟可调用对象

object.__call__(self[args...])

此方法会在实例作为一个函数被“调用”时被调用;如果定义了此方法,则 x(arg1, arg2, ...) 就相当于 x.__call__(arg1, arg2, ...) 的快捷方式。

3.3.6. Emulating callable objects

object.__call__(self[args...])

Called when the instance is “called” as a function; if this method is defined, x(arg1, arg2, ...) is a shorthand for x.__call__(arg1, arg2, ...).

 

 

3. Data model — Python 3.8.3 documentation https://docs.python.org/3/reference/datamodel.html#object.__call__

 

 

 

 

 

 

 

https://www.php.net/manual/zh/function.array-map.php

array_map

(PHP 4 >= 4.0.6, PHP 5, PHP 7)

array_map — 为数组的每个元素应用回调函数

说明

array_map ( callable $callback , array $array1 [, array $... ] ) : array

array_map():返回数组,是为 array1 每个元素应用 callback函数之后的数组。 callback 函数形参的数量和传给 array_map() 数组数量,两者必须一样。

参数

 

callback

回调函数,应用到每个数组里的每个元素。

array1

数组,遍历运行 callback 函数。

...

数组列表,每个都遍历运行 callback 函数。

返回值

返回数组,包含 callback 函数处理之后 array1 的所有元素。

范例

 

Example #1 array_map() 例子

<?php
function cube($n)
{
    return($n * $n * $n);
}

$a = array(1, 2, 3, 4, 5);
$b = array_map("cube", $a);
print_r($b);
?>

这使得 $b 成为:

Array
(
    [0] => 1
    [1] => 8
    [2] => 27
    [3] => 64
    [4] => 125
)

 

Example #2 array_map() 使用匿名函数 (PHP 5.3.0 起)

<?php
$func = function($value) {
    return $value * 2;
};

print_r(array_map($func, range(1, 5)));
?>

 

https://www.php.net/manual/en/function.array-map.php

array_map

(PHP 4 >= 4.0.6, PHP 5, PHP 7)

array_map — Applies the callback to the elements of the given arrays

Description

array_map ( callable $callback , array $array1 [, array $... ] ) : array

array_map() returns an array containing the results of applying the callback function to the corresponding index of array1 (and ... if more arrays are provided) used as arguments for the callback. The number of parameters that the callback function accepts should match the number of arrays passed to array_map().

Parameters

 

callback

Callback function to run for each element in each array.

NULL can be passed as a value to callback to perform a zip operation on multiple arrays. If only array1 is provided, array_map() will return the input array.

array1

An array to run through the callback function.

...

Supplementary variable list of array arguments to run through the callback function.

Return Values

Returns an array containing the results of applying the callback function to the corresponding index of array1 (and ... if more arrays are provided) used as arguments for the callback.

The returned array will preserve the keys of the array argument if and only if exactly one array is passed. If more than one array is passed, the returned array will have sequential integer keys.

 

 

 

 

 
 
Callable 是 Python 标准库 typing 模块中的一个类型
from typing import Callable
 
# 表示一个接受任意参数并返回任意类型的可调用对象
Callable[..., Any]
 
# 表示一个接受两个 int 类型参数并返回 str 类型的可调用对象
Callable[[int, int], str]

[使用方法]

1、函数参数中使用 Callable
from typing import Callable
 
def apply(func: Callable[[int], int], x: int) -> int:
    return func(x)
 
def square(n: int) -> int:
    return n * n
 
result = apply(square, 5)
print(result)  # 输出 25


在上述代码中,apply 函数接受一个可调用对象 func,该可调用对象接受一个 int 类型的参数并返回一个 int 类型的值。

2、返回值为 Callable
from typing import Callable
 
def make_adder(n: int) -> Callable[[int], int]:
    def adder(x: int) -> int:
        return x + n
    return adder
 
add_five = make_adder(5)
print(add_five(3))  # 输出 8

在这个例子中,make_adder 函数返回一个可调用对象 adder,该可调用对象接受一个 int 类型的参数并返回一个 int 类型的值。


[实践]
1、回调函数
在异步编程、事件驱动编程等场景中,回调函数是一种常见的模式。使用 Callable 类型提示可以明确回调函数的参数和返回值类型。

from typing import Callable
 
def async_operation(callback: Callable[[int], None]) -> None:
    # 模拟异步操作
    result = 42
    callback(result)
 
def print_result(result: int) -> None:
    print(f"Result: {result}")
 
async_operation(print_result)

2、[高阶函数]
高阶函数是指接受一个或多个函数作为参数,或返回一个函数的函数。使用 Callable 类型提示可以提高高阶函数的可读性和可维护性。

from typing import Callable
 
def filter_list(lst: list[int], predicate: Callable[[int], bool]) -> list[int]:
    return [x for x in lst if predicate(x)]
 
def is_even(n: int) -> bool:
    return n % 2 == 0
 
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = filter_list(numbers, is_even)
print(even_numbers)  # 输出 [2, 4, 6]

 
# Functions are First-Class Citizens in Python 一等公民


https://cn.bing.com/search?form=MOZSBR&pc=MOZI&q=python++function++First+class+citizens
 
co_freevars tuple of names of free variables (referenced via a function’s closure)
 
 
 
posted @ 2020-06-01 12:38  papering  阅读(462)  评论(0)    收藏  举报