php利用反射真正实现多继承(非接口模拟)
昨天我在写PHP程序的时候,无意发现在PHP的::操作符非常强大,不仅仅是只用在访问parent,sel,静态成员属性、常量上面,其实他的功能强大了去了
。
这个符号在PHP中实际上叫做范围解析符,这是PHP官方的解释php.net/manual/zh/language.oop5.paamayim-nekudotayim.php。但是官方中文部分只是简单的介绍了
访问parent,sel,静态成员属性、常量的作用,而下面英文部分,可能由于咱们这些吊死对英文不好的缘故,就没看下去了,实现上,下面还有一个强大的特性,我们大家都没看到。
什么叫范围操作符呢,可能很多人都没有认真的去分析过,这几个字,根据我这两年的编程的理解,我觉得应该是定义了类中的成员属性和成员方法的所在范围,感觉有点类似命名空间的感觉。
而self::method();其实指的就是调用当前范围里的method方法,那parent自然指的就是父类所在范围,这就是为什么,我们在子类中
覆盖父类的方法,我们仍然可以用parent::method()访问的原因。大家还要注意一点,self永远指向的是其实声明位置所在类本身和而
parent永远指向的是声明位置所在类的父类,不会受继承上下文的影响而改变。
前面讲的这些可能大家有些人已经知道了,上面说过::在PHP中叫范围解析操作符,上面我说过了既然,parent和self都能指向一个类范围的代名词,那试想下,我们能不能用类名指向某个范围呢,答案当然是可以的。我们可以这样
- class a{
- public function demo(){
- echo 'abc';
- }
- }
- a::demo();
大家肯定又疑惑这跟多继承有什么关系呢,别急,心急吃不了热豆腐的!!!!!
其实这个范围操作符还有一个很大的特性,就是当在类外部调用一个非静态公共方法时,方法内部的$this指针会指向他当前运行所在对象本身(宿主对象),
当一个类实例化时,方法里面$this永远指向的实例化后的对象本身,为什么呢,因为这个方法是被这个对象调用执行的,所以这个对象就是他的宿主对象。而
刚才我们直接在全局调中调用这个方法时,由于这个方法运行时不在任何对象中,所以不存在任何宿主对象,所以如果在方法里面写$this的话会报致命错误。
那怎么样才能拥有宿主对象,然后直接调用。仔细看我刚才讲的同学可能注意到,我刚才说过"因为这个方法是被这个对象调用执行的,所以这个对象就是他的宿主
对象"。所以理论上说,我们只要改变执行这个方法的所在环境,就可以改变他的宿主对象。下面我们来实验下
class a{
public function say_name(){
echo 'my name is'.$this->name;
}
}class b{
public $name='xbs530';
public function run(){
a::say_name();
}
}$o=new b;
$o->run();
大家猜会输出什么。。。。。。。
大家可以动手做一下试验。。。。。由于a::say_name()是被对象$o调用的,所以方法里面的$this自然指向了对象$o。很神奇吧。。。。
这个我之前发的那个PHP范围解析操作符中都有讲,好了基础就讲到这里,下面直接上多继承的代码了,欢迎吐槽。。。。。
/*
多继承基类
注:要想实现类多继承,必需首先继承此基类
*/
class multi_extends{
public function __construct(){
$this->_init_extends();
}
protected function _init_extends(){
if(property_exists($this,'_extends'))
{
$extends=&$this->_extends;
foreach($extends as $class)
{
$this->_extends($class);
}
}
}
public function _extends($class_name){
//分析目标
$ref = new ReflectionClass($class_name);
//继承公共属性
$property_list=$ref->getProperties(ReflectionProperty::IS_PUBLIC);
foreach($property_list as $property)
{
$property_name=$property->name;
$property_value=$property->getValue(new $class_name);
if($property_name==='_extends')
{
foreach($property_value as $c)
{
$this->_extends[]=$c;
}
}else{
if(!property_exists($this,$property_name))
{
$this->{$property->name}=$property_value;
}
}
}
//继承公共方法
$method_list=$ref->getMethods(ReflectionMethod::IS_PUBLIC);
foreach($method_list as $method)
{
$this->_extends_method[$method->name]=$method->class;
}
}
function __call($m,$a){
if($c=$this->_extends_method[$m])
{
eval("$c::$m(".'$a'.");");
}
}
}header('content-type:text/html;charset=utf-8');
class a{
public $a=5;
public function say_name(){
echo '我叫'.$this->name.'<br>';
}
}class b{
function say_age(){
echo '我今年'.$this->age.'岁<br>';
}
}class c extends multi_extends{
public $_extends=array('a','b');
public function say_hellow(){
echo 'hellow '.$this->name.'<br>';
}
}class d{
function say_goodbye(){
echo 'goodbye '.$this->name.'<br>';
}
}class persion extends multi_extends{
public $_extends=array('c','d');
public $name="熊宝山";
public $age="20";
}//执行继承后的方法
$o=new persion();
$o->say_name();
$o->say_age();
$o->say_hellow();
$o->say_goodbye();
php利用反射真正实现多继承(非接口模拟)的更多相关文章
- Atitit利用反射获取子类 集合 以及继承树
Atitit利用反射获取子类 集合 以及继承树 想从父类往下找子类的确是不可能的,要知道只要类不是final的话谁都有继承它的自由不需要事前通知父类. Eclipse实现不是重父类开始找而是重子类往回 ...
- Python基础篇【第3篇】: Python异常处理、反射、动态导入、利用反射的web框架
异常处理 什么是异常? 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行. 一般情况下,在Python无法正常处理程序时就会发生一个异常.异常是Python对象,表示一个错误.当P ...
- c#反射机制学习和利用反射获取类型信息
反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得每个成员的 ...
- 静态代理和利用反射形成的动态代理(JDK动态代理)
代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...
- [.net 面向对象程序设计进阶] (20) 反射(Reflection)(上)利用反射技术实现动态编程
[.net 面向对象程序设计进阶] (20) 反射(Reflection)(上)利用反射技术实现动态编程 本节导读:本节主要介绍什么是.NET反射特性,.NET反射能为我们做些什么,最后介绍几种常用的 ...
- <五>JDBC_利用反射及JDBC元数据编写通用的查询方法
此类针对javaBean类写了一个通用的查询方法,List<javaBean> 通用查询更新中...:通过学习,深刻体会到学会反射就等于掌握了java基础的半壁江山! 一.使用JDBC驱动 ...
- .NET 利用反射将对象数据添加到数据库
.NET 利用反射将对象数据添加到数据库 一些小型的项目,在不使用其他的框架(LINQ,NHibernate,EF等等框架)的前提下,这时候一些反复的增删改查就会让我们感到极其的繁琐,厌烦,为了避 ...
- 第十篇 一个利用反射实现的Excel导出
前些天写了个导出Excel的公共类,因为项目中也需要上传Excel,没有利用Office组件,(PS:Office在上传文件时候,Excel进程无法关闭,会导致上传和打开失败)有的说利用Kill把进程 ...
- 优化Servlet:(利用反射的思想)
1.创建BaseServlet (重写父类的service方法) package com.learning.web.servlet; import java.io.IOException; impor ...
随机推荐
- 爱,死亡和机器人 第十四集 齐马蓝 中文字幕(Python处理utf8文件获取想要的内容)
处理代码 file = "a.srt" fi = open(file, mode='r') a = fi.readline() i = 1 while len(str(a)) != ...
- 【Oracle】DBA_AUDIT_TRAIL表SES_ACTIONS字段对应的操作列表
SES_ACTIONS字段共包含16个字符,初始状态都为“-”,当被审计的对象被操作后,SES_ACTIONS会在相应的位置作出标识,标识为“S”的代表操作成功,标识为“F”的代表操作失败,16个位置 ...
- mysql简单语句
创建名为user的数据库: create database user; 显示所有数据库: show databases; 选择名为user的数据库: use user; 显示所有表: show tab ...
- Linux学习笔记(Redhat)
一.开始 linux平台上的开发 vi.gcc.gdb.make.jdk.tomcat.mysql. linux基本操作 c语言功底<c专家编程>和java语言 学习unix高级编程 &l ...
- BigDataMini导论
Q: BigDataMini从大量数据中挖掘有用的信息,对AI有何意义? A: 随着智能硬件化,DataMini可以作为AI的一种数据筛选方法,简化AI的设计进程.
- Shiro从数据表中初始化资源和权限
之前在测试的Web工程下,我们在applicationContext.xml中配置了shiroFilter资源拦截器信息: <bean id="shiroFilter" cl ...
- redis启动出错 Creating Server TCP listening socket 127.0.0.1:6379: bind: No error解决办法
windows下安装Redis第一次启动报错: [2368] 21 Apr 02:57:05.611 # Creating Server TCP listening socket 127.0.0.1: ...
- 常用css和js内容
1.让一个200x200的div在不同分辨率屏幕上下左右居中. <div class="box"></div> <style type="t ...
- [SDOI2018]战略游戏(圆方树+虚树)
喜闻乐见的圆方树+虚树 图上不好做,先建出圆方树. 然后答案就是没被选到的且至少有两条边可以走到被选中的点的圆点的数量. 语文不好,但结论画画图即可得出. 然后套路建出虚树. 发现在虚树上DP可以得出 ...
- HDU-1695 GCD(求一个区间内与一个数互质的个数)
题意: 给你一个T,是样例的个数,接下来是五个数l1,r1,l2,r2,k 前四个数代表两个区间(l1,r1),(l2,r2)这个题l1=1,l2=1; 取x1属于(1,r1),x2属于(1,r2) ...