zoukankan      html  css  js  c++  java
  • 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 析构中
    复制代码
  • 相关阅读:
    Hibernate学习笔记1.2(Annotation版本的Helloworld)
    Hibernate学习笔记1.1(简单插入数据)
    Java 分页与原理(上)
    触发器实例讲解
    URLRewrite 实现方法详解
    一个数组:1,1,2,3,5,8,13,21...+m,求第30位数是多少?用递归实现;(常考!!!)
    面向对象
    ajax 判断账户密码 调取数据模糊查询 时钟
    asp.net 类,接口
    asp.net get图
  • 原文地址:https://www.cnblogs.com/wht123/p/14245282.html
Copyright © 2011-2022 走看看