PHP:面向对象学习笔记,重点模拟Mixin(掺入)

相对于Python、Node和Ruby来说PHP算是一门容易学习和使用的语言,因为这个特点也使其成为WEB开发领域的佼佼者,本文记录一下我对PHP面向对象部分的学习笔记。

先来一个复杂的例子:Mixin(掺入)

Ruby和Python可以用非常漂亮的语法支持掺入,PHP能实现吗?让我们试试吧。

参考其他语言的掺入示例可以查看这篇文章:设计原则:请重新审视“多重继承”,找机会拥抱一下“掺入(Mixin)”

PHP5.4提供的有Traits机制可以方便的模拟掺入,下面的示例是采用5.3版本的机制模拟出来的。

期望的最终效果

PHP:面向对象学习笔记,重点模拟Mixin(掺入)
 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();
PHP:面向对象学习笔记,重点模拟Mixin(掺入)

是不是特别像C#的扩展方法。

实现代码

PHP:面向对象学习笔记,重点模拟Mixin(掺入)
 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 }
PHP:面向对象学习笔记,重点模拟Mixin(掺入)

看不明白不要紧,继续看下文,回头再看这个。

面向对象

很多信息在注释中可以看到,在文中不会再重复一遍。

基本的类型声明

代码

PHP:面向对象学习笔记,重点模拟Mixin(掺入)
 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 ?>
PHP:面向对象学习笔记,重点模拟Mixin(掺入)

运行结果

1 // 公共成员
2 // 私共成员

继承:实现继承和接口继承

代码

PHP:面向对象学习笔记,重点模拟Mixin(掺入)
 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 ?>
PHP:面向对象学习笔记,重点模拟Mixin(掺入)

运行结果

1 头
2 内容
3 尾
4 游戏中。。。
5 析构中

静态成员

代码

PHP:面向对象学习笔记,重点模拟Mixin(掺入)
 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 ?>
PHP:面向对象学习笔记,重点模拟Mixin(掺入)

运行结果

PHP:面向对象学习笔记,重点模拟Mixin(掺入)
 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 子类常量
PHP:面向对象学习笔记,重点模拟Mixin(掺入)

又是魔法方法

代码

PHP:面向对象学习笔记,重点模拟Mixin(掺入)
 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 ?>
PHP:面向对象学习笔记,重点模拟Mixin(掺入)

输出结果

1 段光伟
2 TRUE
3 FALSE
4 saySomethingarray(2) { [0]=> string(3) "hi!" [1]=> string(12) "how are you!" } 

可调用对象(其实还是魔法方法)

代码

PHP:面向对象学习笔记,重点模拟Mixin(掺入)
 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 ?>
PHP:面向对象学习笔记,重点模拟Mixin(掺入)

输入结果

1 int(5) int(5) bool(true) 

Reflection(反射)

代码

PHP:面向对象学习笔记,重点模拟Mixin(掺入)
 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 ?>
PHP:面向对象学习笔记,重点模拟Mixin(掺入)

输出结果

PHP:面向对象学习笔记,重点模拟Mixin(掺入)
1 Child
2 Array ( [0] => __construct [1] => play [2] => __destruct [3] => write ) 
3 Array ( [content] => [StaticProperty] => 子类静态属性
4 ) 
5 游戏中。。。
6 析构中
PHP:面向对象学习笔记,重点模拟Mixin(掺入)
上一篇:vue源码学习(九)Vue.mixin方法


下一篇:JS获取图片的原始宽度和高度,兼容IE7,8