PHP:面向对象学习笔记,重点模拟Mixin(掺入)
背景
相对于Python、Node和Ruby来说PHP算是一门容易学习和使用的语言,因为这个特点也使其成为WEB开发领域的佼佼者,本文记录一下我对PHP面向对象部分的学习笔记。
先来一个复杂的例子:Mixin(掺入)
Ruby和Python可以用非常漂亮的语法支持掺入,PHP能实现吗?让我们试试吧。
参考其他语言的掺入示例可以查看这篇文章:设计原则:请重新审视“多重继承”,找机会拥抱一下“掺入(Mixin)”。
PHP5.4提供的有Traits机制可以方便的模拟掺入,下面的示例是采用5.3版本的机制模拟出来的。
期望的最终效果
1 class Playable 2 { 3 public function play($that) 4 { 5 echo "一起玩吧,".$that->name; 6 } 7 } 8 9 class Base extends _Object 10 { 11 public $name = "段光伟<br/>"; 12 } 13 14 class Child extends Base {} 15 16 Base::implement(new Playable()); 17 18 $base = new Base(); 19 $child = new Child(); 20 21 $base->play(); 22 $child->play();
是不是特别像C#的扩展方法。
实现代码
1 class _Object 2 { 3 private static $mixins = array(); 4 5 public static function implement($target) 6 { 7 $class = get_called_class(); 8 9 if (!isset(self::$mixins[$class])) 10 { 11 self::$mixins[$class] = array(); 12 } 13 14 foreach (get_class_methods($target) as $method) 15 { 16 self::$mixins[$class][$method] = $target; 17 } 18 } 19 20 public function class_name() 21 { 22 return self::get_class($this); 23 } 24 25 public function __call($method, $params) 26 { 27 $params = array_merge(array($this), $params); 28 $class = $class = get_called_class(); 29 30 $mixin = $this->find_mixin($class, $method); 31 32 call_user_func_array($mixin, $params); 33 } 34 35 private function find_mixin($class, $method) 36 { 37 while ($class != NULL) 38 { 39 if (isset(self::$mixins[$class][$method])) 40 { 41 $target = self::$mixins[$class][$method]; 42 43 return array($target, $method); 44 } 45 46 $class = get_parent_class($class); 47 } 48 49 throw new MethodException("方法 $method 不存在"); 50 } 51 }
看不明白不要紧,继续看下文,回头再看这个。
面向对象
很多信息在注释中可以看到,在文中不会再重复一遍。
基本的类型声明
代码
1 <?php 2 3 header("content-type: text/html; charset=utf-8"); 4 5 // 类型不能有修饰符。 6 // 成员以应用访问修饰符号,一共有三种访问修饰符:public、protected和private。 7 class TestClass { 8 // 属性默认访问级别是private。 9 private $private_property = "私共成员<br/>"; 10 11 // var形式的默认访问级别是public。 12 var $public_property = "公共成员<br/>"; 13 14 // 方法默认访问级别是public。 15 public function public_method() { 16 echo $this->private_property; 17 } 18 } 19 20 $test = new TestClass(); 21 22 echo $test->public_property; 23 $test->public_method(); 24 25 ?>
运行结果
1 // 公共成员 2 // 私共成员
继承:实现继承和接口继承
代码
1 <?php 2 3 header("content-type: text/html; charset=utf-8"); 4 5 /* 6 * 使用interface关键字可以声明接口,接口以及接口的成员不能有任何修饰符。 7 */ 8 interface Playable { 9 function play(); 10 } 11 12 /* 13 * 使用abstract关键字可以声明抽象类和方法。 14 */ 15 abstract class Base { 16 private $header = ""; 17 private $rooter = ""; 18 19 public function __construct($header, $rooter) { 20 $this->header = $header; 21 $this->rooter = $rooter; 22 } 23 24 public function write() { 25 $this->writeHeader(); 26 $this->writeContent(); 27 $this->writeRooter(); 28 } 29 30 private function writeHeader() { 31 echo $this->header."<br/>"; 32 } 33 34 private function writeRooter() { 35 echo $this->rooter."<br/>"; 36 } 37 38 protected abstract function writeContent(); 39 } 40 41 /* 42 * 使用final关键字可以禁止类型或方法被重写。 43 * 使用parent::在重写的方法里调用父类型的方法。 44 */ 45 final class Child extends Base implements Playable { 46 private $content = ""; 47 48 public function __construct($header, $rooter, $content) { 49 parent::__construct($header, $rooter); 50 51 $this->content = $content; 52 } 53 54 protected function writeContent() { 55 echo $this->content."<br/>"; 56 } 57 58 public function play() { 59 echo "游戏中。。。<br/>"; 60 } 61 62 public function __destruct() { 63 echo "析构中<br/>"; 64 } 65 } 66 67 $child = new Child("头", "尾", "内容"); 68 $child->write("段光伟"); 69 $child->play(); 70 71 ?>
运行结果
1 头 2 内容 3 尾 4 游戏中。。。 5 析构中
静态成员
代码
1 <?php 2 3 header("content-type: text/html; charset=utf-8"); 4 5 class StaticBaseClass { 6 public static $StaticProperty = "父类静态属性<br/>"; 7 const MAX = "父类常量<br/>"; 8 9 public static function staticMethod() { 10 /* 在内部可以使用类名或self关键字,但是self访问的其定义时的类型,而不是运行时的类型, 11 * 这在子类和父类里有同名的静态成员和常量时会出现问题,为了避免这个问题可以使用static 12 * 关键字。 13 */ 14 15 echo get_called_class()." self::\$StaticProperty ".self::$StaticProperty; 16 echo get_called_class()." StaticBaseClass::\$StaticProperty ".StaticBaseClass::$StaticProperty; 17 echo get_called_class()." static::\$StaticProperty ".static::$StaticProperty; 18 19 echo get_called_class()." self::MAX ".self::MAX; 20 echo get_called_class()." StaticBaseClass::MAX ".StaticBaseClass::MAX; 21 echo get_called_class()." static::MAX ".static::MAX; 22 } 23 } 24 25 class StaticChildClass extends StaticBaseClass { 26 public static $StaticProperty = "子类静态属性<br/>"; 27 const MAX = "子类常量<br/>"; 28 } 29 30 // 在外部必须使用类名访问。 31 StaticBaseClass::StaticMethod(); 32 echo StaticBaseClass::$StaticProperty; 33 echo StaticBaseClass::MAX; 34 35 // 在子类中可以调用父类的静态成员和常量。 36 StaticChildClass::StaticMethod(); 37 echo StaticChildClass::$StaticProperty; 38 echo StaticChildClass::MAX; 39 40 ?>
运行结果
1 StaticBaseClass self::$StaticProperty 父类静态属性 2 StaticBaseClass StaticBaseClass::$StaticProperty 父类静态属性 3 StaticBaseClass static::$StaticProperty 父类静态属性 4 StaticBaseClass self::MAX 父类常量 5 StaticBaseClass StaticBaseClass::MAX 父类常量 6 StaticBaseClass static::MAX 父类常量 7 父类静态属性 8 父类常量 9 StaticChildClass self::$StaticProperty 父类静态属性 10 StaticChildClass StaticBaseClass::$StaticProperty 父类静态属性 11 StaticChildClass static::$StaticProperty 子类静态属性 12 StaticChildClass self::MAX 父类常量 13 StaticChildClass StaticBaseClass::MAX 父类常量 14 StaticChildClass static::MAX 子类常量 15 子类静态属性 16 子类常量
又是魔法方法
代码
1 <?php 2 3 header("content-type: text/html; charset=utf-8"); 4 5 /* 6 * 什么叫魔法方法:被解释器在某些特殊情况下调用的实例方法。 7 */ 8 class WebDeveloper { 9 public $info = array(); 10 11 // 当执行赋值时,而目标成员不存在会调用此方法。 12 public function __set($item, $value) { 13 $this->info[$item] = $value; 14 } 15 16 // 当执行取值时,而目标成员不存在会调用此方法。 17 public function __get($item) { 18 return $this->info[$item]; 19 } 20 21 // 当执行isset方法时,而目标成员不存在会调用此方法。 22 public function __isset($item) { 23 return isset($this->info[$item]); 24 } 25 26 // 当执行unset方法时,而目标成员不存在会调用此方法。 27 public function __unset($item) { 28 unset($this->info[$item]); 29 } 30 31 // 当执行方法调用时,而目标方法不存在会调用此方法。 32 public function __call($method_name, $args) { 33 echo $method_name, var_dump($args), "<br/>"; 34 } 35 } 36 37 $developer = new WebDeveloper(); 38 $developer->name = "段光伟"; 39 40 echo "{$developer->name}<br/>"; 41 echo (isset($developer->name) ? "TRUE" : "FALSE")."<br/>"; 42 unset($developer->name); 43 echo (isset($developer->name) ? "TRUE" : "FALSE")."<br/>"; 44 45 $developer->saySomething('hi!','how are you!'); 46 47 ?>
输出结果
1 段光伟 2 TRUE 3 FALSE 4 saySomethingarray(2) { [0]=> string(3) "hi!" [1]=> string(12) "how are you!" }
可调用对象(其实还是魔法方法)
代码
1 <?php 2 header("content-type: text/html; charset=utf-8"); 3 4 class CallableClass 5 { 6 public function __invoke($x) 7 { 8 var_dump($x); 9 } 10 } 11 12 $obj = new CallableClass; 13 14 $obj(5); 15 call_user_func_array($obj, array(5)); 16 var_dump(is_callable($obj)); 17 18 ?>
输入结果
1 int(5) int(5) bool(true)
Reflection(反射)
代码
1 <?php 2 3 header("content-type: text/html; charset=utf-8"); 4 5 /* 6 * 使用interface关键字可以声明接口,接口以及接口的成员不能有任何修饰符。 7 */ 8 interface Playable { 9 function play(); 10 } 11 12 /* 13 * 使用abstract关键字可以声明抽象类和方法。 14 */ 15 abstract class Base { 16 private $header = ""; 17 private $rooter = ""; 18 19 public static $StaticProperty = "父类静态属性<br/>"; 20 const MAX = "父类常量<br/>"; 21 22 public function __construct($header, $rooter) { 23 $this->header = $header; 24 $this->rooter = $rooter; 25 } 26 27 public function write() { 28 $this->writeHeader(); 29 $this->writeContent(); 30 $this->writeRooter(); 31 } 32 33 private function writeHeader() { 34 echo $this->header."<br/>"; 35 } 36 37 private function writeRooter() { 38 echo $this->rooter."<br/>"; 39 } 40 41 protected abstract function writeContent(); 42 } 43 44 /* 45 * 使用final关键字可以禁止类型或方法被重写。 46 * 使用parent::在重写的方法里调用父类型的方法。 47 */ 48 final class Child extends Base implements Playable { 49 public $content = ""; 50 public static $StaticProperty = "子类静态属性<br/>"; 51 const MAX = "子类常量<br/>"; 52 53 public function __construct($header, $rooter, $content) { 54 parent::__construct($header, $rooter); 55 56 $this->content = $content; 57 } 58 59 protected function writeContent() { 60 echo $this->content."<br/>"; 61 } 62 63 public function play() { 64 echo "游戏中。。。<br/>"; 65 } 66 67 public function __destruct() { 68 echo "析构中"; 69 } 70 } 71 72 $child = new Child("开始", "结束", "内容"); 73 74 echo get_class($child).'<br/>'; 75 print_r(get_class_methods(get_class($child))); 76 echo '<br/>'; 77 print_r(get_class_vars(get_class($child))); 78 echo '<br/>'; 79 echo $child->{"play"}(); 80 ?>
输出结果
1 Child 2 Array ( [0] => __construct [1] => play [2] => __destruct [3] => write ) 3 Array ( [content] => [StaticProperty] => 子类静态属性 4 ) 5 游戏中。。。 6 析构中
备注
PHP属于:静态类型、鸭子类型、弱类型、解释执行的语言 ,后面详细介绍这些概念及其对应的语言特色。