【PHP5.3的新增、改进】匿名函数
也叫闭包(Closures), 经常被用来临时性地创建一个无名函数,用于回调函数等用途。
$func = function ($arg) { print $arg; }; $func("Hello World");
<?php $f = function () { return 100; }; function testClosure(Closure $callback) { return $callback(); } $a = testClosure($f); print_r($a); //100 exit;如果要调用一个类里面的匿名函数呢
<?php class C { public static function testC() { return function ($i) { return $i + 100; }; } } function testClosure(Closure $callback) { return $callback(13); } $a = testClosure(C::testC()); print_r($a);exit;其中的C::testC()返回的是一个funciton,我们就需要将“一个匿名函数绑定到一个类中”。
<?php class A{ public $base = 100; } $f = function () { return $this->base + 3; }; $a = Closure::bind($f, new A); print_r($a());f这个匿名函数中莫名奇妙的有个this,这个this关键词就是说明这个匿名函数是需要绑定在类中的。绑定之后,就好像A中有这么个函数一样,但是这个函数是public还是private,bind的最后一个参数就说明了这个函数的可调用范围 匿名函数还可以用 use 关键字来捕捉外部变量:
function arrayPlus($array, $num) { array_walk($array, function (&$v) use ($num) { $v += $num; }); }上面的代码定义了一个 arrayPlus() 函数(这不是匿名函数), 它会将一个数组($array)中的每一项,加上一个指定的数字($num).在 arrayPlus() 的实现中, 我们使用了 array_walk() 函数,它会为一个数组的每一项执行一个回调函数,即我们定义的匿名函数。在匿名函数的参数列表后,我们用 use 关键字将匿名函数外的 $num 捕捉到了函数内,以便知道到底应该加上多少。 PHP参数类型约束,不论是接口,抽象类,函数,方法,在5.3+以上版本都可以使用,不过目前只能声明 array,object ,可执行类型( callable.Closure)这3种.ConnectionInterface就是属于object
public function addConnection($name, ConnectionInterface $connection) { $this->connections[$name] = $connection; }后期静态绑定PHP的继承模型中有一个存在已久的问题,那就是在父类中引用扩展类的最终状态比较困难。
<?php class ParentBase { static $property = 'Parent Value'; public static function render() { return self::$property; } } class Descendant extends ParentBase { static $property = 'Descendant Value'; } //output: Parent Value echo Descendant::render();在这个例子中,render()方法中使用了self关键字,这是指ParentBase类而不是指Descendant类。在 ParentBase::render()方法中没法访问$property的最终值。为了解决这个问题,需要在子类中重写render()方法。 通过引入延迟静态绑定功能,可以使用static作用域关键字访问类的属性或者方法的最终值
<?php class ParentBase { static $property = 'Parent Value'; public static function render() { return static::$property; } } class Descendant extends ParentBase { static $property = 'Descendant Value'; } //output: Descendant Value echo Descendant::render();PHP的面向对象体系中,提供了若干“魔术方法”,用于实现类似其他语言中的“重载”,如在访问不存在的属性、方法时触发某个魔术方法。
__call($funcname, $arguments)
__callStatic($funcname, $arguments)
参数说明:
$funcname String 调用的不存在的方法名称。
$arguments Array 调用方法时所带的参数。
__invoke魔术方法会在将一个对象作为函数调用时被调用:
class A { public function __invoke($args) { print "A::__invoke(): {$args}"; } } $a = new A; //output: A::__invoke(): Hello World $a("Hello World");__callStatic则会在调用一个不存在的静态方法时被调用,有了__callStatic,可以省不少代码了。而且这个方法支持在子类中调用,配合上get_called_class,子类也一起魔术了
<?php class ActiveRecordBase { /** As of PHP 5.3.0 */ public static function __callStatic($func, $arguments) { if ($func == 'getById') { $id = $arguments[0]; return get_called_class() . '(' . $id . ')'; } throw new Exception('Invalid method : ' . $name); } } class Person extends ActiveRecordBase { } // output: Person(123) echo Person::getById(123);
__call 当要调用的方法不存在或权限不足时,会自动调用__call 方法。
<?php class Db { private $sql = array( "field" => "", "where" => "", "order" => "", "limit" => "", "group" => "", "having" => "", ); // 连贯操作调用field() where() order() limit() group() having()方法,组合sql语句 function __call($methodName, $args) { // 将第一个参数(代表不存在方法的方法名称),全部转成小写方式,获取方法名称 $methodName = strtolower($methodName); // 如果调用的方法名和成员属性数组$sql下标对应上,则将第二个参数给数组中下标对应的元素 if (array_key_exists($methodName, $this->sql)) { $this->sql[$methodName] = $args[0]; } else { echo '调用类' . get_class($this) . '中的方法' . $methodName . '()不存在'; } // 返回自己对象,则可以继续调用本对象中的方法,形成连贯操作 return $this; } // 输出连贯操作后组合的一个sql语句,是连贯操作最后的一个方法 function select() { echo "SELECT {$this->sql['field']} FROM user {$this->sql['where']} {$this->sql['order']} {$this->sql['limit']} {$this->sql['group']} {$this->sql['having']}"; } } $db = new Db(); // 连贯操作 $db->field('sex, count(sex)') ->where('where sex in ("男","女")') ->group('group by sex') ->having('having avg(age) > 25') ->select(); ?>
命名空间一个最明确的目的就是解决重名问题,PHP中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误。这种情况下只要避免命名重复就可以解决,最常见的一种做法是约定一个前缀。
<?php //创建空间Blog namespace Blog; class Comment { } //非限定名称,表示当前Blog空间 //这个调用将被解析成 Blog\Comment(); $blog_comment = new Comment(); //限定名称,表示相对于Blog空间 //这个调用将被解析成 Blog\Article\Comment(); $article_comment = new Article\Comment(); //类前面没有反斜杆\ //完全限定名称,表示绝对于Blog空间 //这个调用将被解析成 Blog\Comment(); $article_comment = new \Blog\Comment(); //类前面有反斜杆\ //完全限定名称,表示绝对于Blog空间 //这个调用将被解析成 Blog\Article\Comment(); $article_comment = new \Blog\Article\Comment(); //类前面有反斜杆\ //创建Blog的子空间Article namespace Blog\Article; class Comment { } ?>别名和导入可以看作是调用命名空间元素的一种快捷方式。PHP并不支持导入函数或常量。 它们都是通过使用use操作符来实现:
<?php namespace Blog\Article; class Comment { } //创建一个BBS空间(我有打算开个论坛) namespace BBS; //导入一个命名空间 use Blog\Article; //导入命名空间后可使用限定名称调用元素 $article_comment = new Article\Comment(); //为命名空间使用别名 use Blog\Article as Arte; //使用别名代替空间名 $article_comment = new Arte\Comment(); //导入一个类 use Blog\Article\Comment; //导入类后可使用非限定名称调用元素 $article_comment = new Comment(); //为类使用别名 use Blog\Article\Comment as Comt; //使用别名代替空间名 $article_comment = new Comt(); ?>php内置的类,不隶属于任何命名空间如果你需要在命名空间中使用须有 \ 声明
new \DateTime();PHP5.4
数组简写形式
<?php //原来的数组写法 $arr = array("key" => "value", "key2" => "value2"); // 简写形式 $arr = ["key" => "value", "key2" => "value2"]; ?>Traits
所谓Traits就是“构件”,是用来替代继承的一种机制。Trait和类相似,但不能被实例化 PHP中无法进行多重继承,但一个类可以包含多个Traits.
<?php trait SayWorld { public $var = 'test'; public function sayHello() { echo 'World!'; } } class MyHelloWorld { // 将SayWorld中的成员包含进来 use SayWorld; } $xx = new MyHelloWorld(); // sayHello()函数是来自SayWorld构件的 $xx->var $xx->sayHello();Traits还有很多神奇的功能,比如包含多个Traits, 解决冲突,修改访问权限,为函数设置别名等等。
<?php class A { public function callFuncTest() { print $this->funcTest(); } public function funcTest() { return "this is A::funcTest().<br/>"; } } $func = "funcTest"; echo A::{$func}(); echo (new A)->funcTest();新增在实例化时访问类成员的特征:
(new MyClass)->xx();新增支持对函数返回数组的成员访问解析
print [1, 2, 3][0];PHP5.5 yield的一个功能就是能有效的降低迭代的内存开销,yield关键字用于当函数需要返回一个迭代器的时候, 逐个返回值.也就是说, 每当产生一个数组元素, 就通过yield关键字返回成一个, 并且函数执行暂停, 当返回的迭代器的next方法被调用的时候, 会恢复刚才函数的执行, 使用上yield实现,里面所有的中间变量都只使用一个内存$i,这样节省的时间和空间都会变小.从上一次被yield暂停的位置开始继续执行, 到下一次遇到yield的时候, 再次返回.
<?php function generators() { for ($i = 1; $i <= 10; $i += 1) { yield $i; } } foreach (generators() as $v) { echo $v; }可以用 list() 在 foreach 中解析嵌套的数组:
$array = [ [1, 2, 3], [4, 5, 6], ]; foreach ($array as list($a, $b, $c)) echo "{$a} {$b} {$c}\n";类名通过::class可以获取
<?php namespace Name\Space; class ClassName {} echo ClassName::class; echo "\n"; ?>PHP7函数 返回值类型声明(注意 … 的边长参数语法在 PHP 5.6 以上的版本中才有)
<?php namespace DesignPatterns\Creational\AbstractFactory; class JsonFactory extends AbstractFactory { public function createText(string $content): Text { return new JsonText($content); } }return的结果必须是Text对象
<?php function arraysSum(array ...$arrays): array { return array_map(function(array $array): int { return array_sum($array); }, $arrays); } print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));