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