PHP其他函数类型介绍
2016-10-11 23:08:18
•
阅读
打赏
PHP 支持可变函数的概念,匿名函数,使用类型约束
可变函数
PHP 支持可变函数的概念。这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它。可变函数可以用来实现包括回调函数,函数表在内的一些用途。
可变函数不能用于例如 echo,print,unset(),isset(),empty(),include,require 以及类似的语言结构。需要使用自己的包装函数来将这些结构用作可变函数。
可变函数示例
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<?phpfunction foo() { echo "In foo()<br />\n";} function bar($arg = '') { echo "In bar(); argument was '$arg'.<br />\n";} // 使用 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()?> |
也可以用可变函数的语法来调用一个对象的方法。
可变方法范例
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?phpclass 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() ?> |
当调用静态方法时,函数调用要比静态属性优先:
Variable 方法和静态属性示例
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?phpclass 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. ?> |
匿名函数
匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。
匿名函数示例
|
1
2
3
4
5
6
|
<?phpecho preg_replace_callback('~-([a-z])~', function ($match) { return strtoupper($match[1]);}, 'hello-world');// 输出 helloWorld?> |
闭包函数也可以作为变量的值来使用。PHP 会自动把此种表达式转换成内置类 Closure 的对象实例。把一个 closure 对象赋值给一个变量的方式与普通变量赋值的语法是一样的,最后也要加上分号:
匿名函数变量赋值示例
|
1
2
3
4
5
6
7
8
9
|
<?php$greet = function($name){ printf("Hello %s\r\n", $name);}; $greet('World');$greet('PHP');?> |
闭包可以从父作用域中继承变量。 任何此类变量都应该用 use 语言结构传递进去。
从父作用域继承变量
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<?php$message = 'hello'; // 没有 "use"$example = function () { var_dump($message);};echo $example(); // 继承 $message$example = function () use ($message) { var_dump($message);};echo $example(); // Inherited variable's value is from when the function// is defined, not when called$message = 'world';echo $example(); // Reset message$message = 'hello'; // Inherit by-reference$example = function () use (&$message) { var_dump($message);};echo $example(); // The changed value in the parent scope// is reflected inside the function call$message = 'world';echo $example(); // Closures can also accept regular arguments$example = function ($arg) use ($message) { var_dump($arg . ' ' . $message);};$example("hello");?> |
以上例程的输出类似于:
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"
这些变量都必须在函数或类的头部声明。 从父作用域中继承变量与使用全局变量是不同的。全局变量存在于一个全局的范围,无论当前在执行的是哪个函数。而 闭包的父作用域是定义该闭包的函数(不一定是调用它的函数)。示例如下:
Closures 和作用域
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
<?php// 一个基本的购物车,包括一些已经添加的商品和每种商品的数量。// 其中有一个方法用来计算购物车中所有商品的总价格,该方法使// 用了一个 closure 作为回调函数。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; // 往购物车里添加条目$my_cart->add('butter', 1);$my_cart->add('milk', 3);$my_cart->add('eggs', 6); // 打出出总价格,其中有 5% 的销售税.print $my_cart->getTotal(0.05) . "\n";// 最后结果是 54.29?> |
匿名函数目前是通过 Closure 类来实现的。
类型约束
PHP 5 可以使用类型约束。函数的参数可以指定必须为对象(在函数原型里面指定类的名字),接口,数组(PHP 5.1 起)或者 callable(PHP 5.4 起)。不过如果使用 NULL 作为参数的默认值,那么在调用函数的时候依然可以使用 NULL 作为实参。
如果一个类或接口指定了类型约束,则其所有的子类或实现也都如此。
类型约束不能用于标量类型如 int 或 string。Traits 也不允许。
类型约束示例
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
<?php//如下面的类class MyClass{ /** * 测试函数 * 第一个参数必须为 OtherClass 类的一个对象 */ public function test(OtherClass $otherclass) { echo $otherclass->var; } /** * 另一个测试函数 * 第一个参数必须为数组 */ public function test_array(array $input_array) { print_r($input_array); }} /** * 第一个参数必须为递归类型 */ public function test_interface(Traversable $iterator) { echo get_class($iterator); } /** * 第一个参数必须为回调类型 */ public function test_callable(callable $callback, $data) { call_user_func($callback, $data); }} // OtherClass 类定义class OtherClass { public $var = 'Hello World';}?> |
函数调用的参数与定义的参数类型不一致时,会抛出一个可捕获的致命错误。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<?php// 两个类的对象$myclass = new MyClass;$otherclass = new OtherClass; // 致命错误:第一个参数必须是 OtherClass 类的一个对象$myclass->test('hello'); // 致命错误:第一个参数必须为 OtherClass 类的一个实例$foo = new stdClass;$myclass->test($foo); // 致命错误:第一个参数不能为 null$myclass->test(null); // 正确:输出 Hello World $myclass->test($otherclass); // 致命错误:第一个参数必须为数组$myclass->test_array('a string'); // 正确:输出数组$myclass->test_array(array('a', 'b', 'c')); // 正确:输出 ArrayObject$myclass->test_interface(new ArrayObject(array())); // 正确:输出 int(1)$myclass->test_callable('var_dump', 1);?> |
类型约束不只是用在类的成员函数里,也能使用在函数里:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<?php// 如下面的类class MyClass { public $var = 'Hello World';} /** * 测试函数 * 第一个参数必须是 MyClass 类的一个对象 */function MyFunction (MyClass $foo) { echo $foo->var;} // 正确$myclass = new MyClass;MyFunction($myclass);?><div>类型约束允许 NULL 值:</div><div> </div><?php /* 接受 NULL 值 */function test(stdClass $obj = NULL) { } test(NULL);test(new stdClass); ?> |


相关推荐
深度学习 -- 损失函数
深度残差网络(Deep Residual Networks (ResNets))
深度学习 -- 激活函数
神经网络训练 -- 调整学习速率
生成对抗网络(GAN)改进与发展
生成对抗网络(GAN)优点与缺点
生成对抗网络(GAN)的训练
生成对抗网络(GAN)基本原理
生成模型与判别模型