Laravel框架原理(一)--Laravel中常用的PHP语法
一.后期静态绑定
自 PHP 5.3.0 起,PHP 增加了一个叫做后期静态绑定的功能,用于在继承范围内引用静态调用的类。用于在继承范围内引用静态调用的类,即在类的继承过程中,使用的类不再是当前类,而是调用的类。
下面介绍一个例子,具体原理和使用可参考 PHP手册 中里面详细介绍后期静态绑定。
Class A{ public static function create(){ $self = new self(); //所在位置的类的实例 $static = new static(); //调用类的实例 return array($self, $static); } } class B extends A{ } $arr = B::create(); var_dump($arr[0]); var_dump($arr[1]);
输出:
object(A)#3 (0) {} object(B)#4 (0) {}
与上述的输出结果相同,在实例化对象中,static会根据运行时候调用的类来决定实例化的对象,而self是根据所在位置的类来决定实例化对象
二.反射
反射机制被多种语言广泛使用,主要用来动态获取类、实例对象、方法等语言构建信息,通过API函数可以实现对这些语言构建信息的动态获取和动态操作等。下面展示一个使用反射的简单例子。
Class ReflectionTest{ public function call(){ echo "hello world"."\r\n"; } } $ref = new ReflectionClass('ReflectionTest'); $inst = $ref->newInstanceArgs(); $inst->call();
上面的例子使用了ReflectionClass,使用ReflectionClass可以获取到类的基本信息,包含类的属性、常量、方法、命名空间、以及对象的实例等等。例子中就是通过newInstanceArgs方法创建一个新的类实例。ReflectionClass类有以下方法:
ReflectionClass::__construct — 初始化 ReflectionClass 类 ReflectionClass::export — 导出一个类 ReflectionClass::getConstant — 获取定义过的一个常量 ReflectionClass::getConstants — 获取一组常量 ReflectionClass::getConstructor — 获取类的构造函数 ReflectionClass::getDefaultProperties — 获取默认属性 ReflectionClass::getDocComment — 获取文档注释 ReflectionClass::getEndLine — 获取最后一行的行数 ReflectionClass::getExtension — 根据已定义的类获取所在扩展的 ReflectionExtension 对象 ReflectionClass::getExtensionName — 获取定义的类所在的扩展的名称 ReflectionClass::getFileName — 获取定义类的文件名 ReflectionClass::getInterfaceNames — 获取接口(interface)名称 ReflectionClass::getInterfaces — 获取接口 ReflectionClass::getMethod — 获取一个类方法的 ReflectionMethod。 ReflectionClass::getMethods — 获取方法的数组 ReflectionClass::getModifiers — 获取类的修饰符 ReflectionClass::getName — 获取类名 ReflectionClass::getNamespaceName — 获取命名空间的名称 ReflectionClass::getParentClass — 获取父类 ReflectionClass::getProperties — 获取一组属性 ReflectionClass::getProperty — 获取类的一个属性的 ReflectionProperty ReflectionClass::getReflectionConstant — Gets a ReflectionClassConstant for a class's constant ReflectionClass::getReflectionConstants — Gets class constants ReflectionClass::getShortName — 获取短名 ReflectionClass::getStartLine — 获取起始行号 ReflectionClass::getStaticProperties — 获取静态(static)属性 ReflectionClass::getStaticPropertyValue — 获取静态(static)属性的值 ReflectionClass::getTraitAliases — 返回 trait 别名的一个数组 ReflectionClass::getTraitNames — 返回这个类所使用 traits 的名称的数组 ReflectionClass::getTraits — 返回这个类所使用的 traits 数组 ReflectionClass::hasConstant — 检查常量是否已经定义 ReflectionClass::hasMethod — 检查方法是否已定义 ReflectionClass::hasProperty — 检查属性是否已定义 ReflectionClass::implementsInterface — 接口的实现 ReflectionClass::inNamespace — 检查是否位于命名空间中 ReflectionClass::isAbstract — 检查类是否是抽象类(abstract) ReflectionClass::isAnonymous — 检查类是否是匿名类 ReflectionClass::isCloneable — 返回了一个类是否可复制 ReflectionClass::isFinal — 检查类是否声明为 final ReflectionClass::isInstance — 检查类的实例 ReflectionClass::isInstantiable — 检查类是否可实例化 ReflectionClass::isInterface — 检查类是否是一个接口(interface) ReflectionClass::isInternal — 检查类是否由扩展或核心在内部定义 ReflectionClass::isIterable — Check whether this class is iterable ReflectionClass::isIterateable — 检查是否可迭代(iterateable) ReflectionClass::isSubclassOf — 检查是否为一个子类 ReflectionClass::isTrait — 返回了是否为一个 trait ReflectionClass::isUserDefined — 检查是否由用户定义的 ReflectionClass::newInstance — 从指定的参数创建一个新的类实例 ReflectionClass::newInstanceArgs — 从给出的参数创建一个新的类实例。 ReflectionClass::newInstanceWithoutConstructor — 创建一个新的类实例而不调用它的构造函数 ReflectionClass::setStaticPropertyValue — 设置静态属性的值 ReflectionClass::__toString — 返回 ReflectionClass 对象字符串的表示形式。
三.trait
相对于多继承语言(如:C++),代码复用问题对于单继承语言(Ruby、PHP、JAVA/、C#)来说需要通过其他方法解决,如Ruby中通过混入类解决。而PHP是通过Trait来实现代码复用。
<?php Class Base{ public function hello(){ echo "Method hello from Base"; } } trait A{ public function hello(){ echo "Method hello from A"."\r\n"; } public function hi(){ echo "Method Hi from A"."\r\n"; } abstract public function abstractFun(); static public function staticFun(){ echo "A Static Method"."\r\n"; } public function getValue(){ static $value; $value++; echo $value."\r\n"; } } trait B{ public function hello(){ parent::hello(); echo "Method hello from B"."\r\n"; } public function hi(){ echo "Method Hi from B"."\r\n"; } } trait AB{ use A, B{ B::hello insteadof A; A::hi insteadof B; } } Class Test extends Base{ use AB; private $value = "value in Test"."\r\n"; public function hi(){ echo "Method Hi from Test"."\r\n"; } public function abstractFun(){ echo $this->value; } } $obj = new Test(); $obj->hello(); $obj->hi(); $obj->staticFun(); $obj->abstractFun();
输出:
<?php Class Base{ public function hello(){ echo "Method hello from Base"."\r\n"; } } trait A{ public function hello(){ echo "Method hello from A"."\r\n"; } public function hi(){ echo "Method Hi from A"."\r\n"; } abstract public function abstractMethod(); static public function staticMethod(){ echo "A Static Method"."\r\n"; } public function staticValue(){ static $value; $value++; echo $value."\r\n"; } } trait B{ public function hello(){ parent::hello(); echo "Method hello from B"."\r\n"; } public function hi(){ echo "Method Hi from B"."\r\n"; } } trait AB{ use A, B{ B::hello insteadof A;//解决名称冲突 A::hi insteadof B; } } Class Test extends Base{ use AB; private $value = "value in Test"."\r\n"; public function hi(){ echo "Method Hi from Test"."\r\n"; } public function abstractMethod(){ echo $this->value; } } $obj = new Test(); $obj->hello(); //输出traitB中的hello方法 $obj->hi(); //输出Test中的方法 $obj->staticMethod();//trait可定义static方法 $obj->abstractMethod();//trait可定义abstract方法 $obj->staticValue();//1 $obj->staticValue();//2 static可使用static变量//1
输出:
Method hello from Base Method hello from B Method Hi from Test A Static Method value in Test 1 2
1.优先级:当前类优先级>trait>基类
2.多个trait组合:通过逗号分隔,使用use关键字列出多个trait
3.冲突的解决:如果两个trait都插入一个同名的方法,若没明确解决冲突会产生一个致命错误。为解决多个trait在同一个类中的命名冲突,需使用insteadof来指定使用冲突方法中的哪一个;也可以用as将其中一个冲突的方法以另一个名称引入。
将上面例子中的 trait AB中使用insteadof的两句删除,会出现以下报错
Trait method hello has not been applied, because there are collisions with other trait methods on AB in D:XXXX.php on line 33
Fatal error: Trait method hello has not been applied, because there are collisions with other trait methods on AB in D:XXXX.php on line 33
4.trait的抽象方法:在trait中使用抽象成员,是的类中必须实现这个抽象方法
5.trait的静态成员:在trait中可以用静态方法和静态变量
6.trait中的属性定义:在trait中同样可以定义属性