PHP 5.4 –特性,闭包和基于原型的编程
根据Wikipedia的说法,基于原型的编程是“一种不存在类的面向对象编程的样式,并且行为重用(在基于类的语言中称为继承)是通过克隆用作原型的现有对象的过程来执行的。”使用魔术方法,特征和匿名函数-现在可以在PHP中实现。
class SimpleXML { use \Prototype; } $SimpleXML = new SimpleXML(); $SimpleXML->load = function( $path ) { if( file_exists( $path )) return simplexml_load_file( $path ); return null; }; $SimpleXML->load = function( $data ) { return simplexml_load_string( $data ); };
先前的代码使用SimpleXML,并包含具有该名称的类声明,该类声明具有单个特征,稍后将显示。然后实例化该类,并将2个匿名函数添加到原型中。使用上面的代码和Prototype特性,以下语句都是可能的。
$doc = $SimpleXML->load( 'test.xml' ); $doc = $SimpleXML->load( 'test' );
第一个方法触发使用simplexml_load_file的Closure,第二个方法分别触发simplexml_load_string。您可能会注意到,两个函数都分配给相同的属性。使用原型特征,可以定义两个具有相同名称和参数数量的函数。这很像传统的方法重载,以前在PHP中是不可能的。以这种方式进行的重载是原始的,并且要求重载的方法满足某些条件,即,如果输入无效,则给定的方法返回null。
trait Prototype { private $_props = array(), $_methods = array(); function &__get( $name ) { if( array_key_exists( $name, $this->_props )) { return $this->_props[$name]; } elseif( array_key_exists( $name, $this->_methods )) { return $this->_methods[$name]; } return null; } function __set( $name, $value ) { if( is_object( $value ) && is_callable( $value )) { if( !array_key_exists( $name, $this->_methods )) { $this->_methods[ $name ] = array(); } if( $value instanceof \Closure ) { $value = $value->bindTo( $this ); } $this->_methods[ $name ][] = $value; } else { $this->_props[ $name ] = $value; } } function __call( $name, $args = array() ) { if( array_key_exists( $name, $this->_methods )) { $methods = $this->_methods[ $name ]; if( is_array( $methods )) { foreach( $methods as $method ) { if( !is_null( $result = call_user_func_array( $method, $args ) ) ) { return $result; } } } } return null; } }
__get方法这很容易解释,因为它只返回一个属性值或一个分别存储在_props和_methods中的Closure。__set方法此方法首先检查该值是否实际上是可调用的。可调用值的一个示例是匿名函数或实现__invoke方法的类。如果该值为Closure,则调用BindTo方法。BindTo就像在普通方法中一样,只允许在闭包中使用$this关键字。最后,如果该值不可调用,则原型将假定它为属性并将其分配给_props数组。__call方法此方法迭代所有匹配的方法,直到返回非null为止。现在上面的原型很好,一个原型。按照基于原型的编程的原始定义,