用trait实现多继承,怎么限定参数类型呢?
使用trait实现多继承,但是无法限定参数的类型。例如下面的例子
trait T{
function t(){
echo 'trait';
}
//省略其他很多代码
}
class B{ } // 假设 B 是一个三方模块
class C extends B{ // 假设 C 必须继承三方模块 B
use T;
}
// 以下客户端代码里面的某些类里面的某些函数可能需要使用到 T 中的若干方法,类似下面这样
function f(T $t){
// 确保 t() 可以被调用,于是限定参数类型,但是有问题
$t->t();
}
f(new C);
沙箱测试发现报错 Fatal error: Uncaught TypeError: f(): Argument #1 ($t) must be of type T, C given
如果把f(T $t)改成f(C $t)则没问题,但这不是我想要的。
如果把trait改成接口的话也不行,因为接口里面不能写函数体。
如果把trait改成类的话也不行,因为 C 已经继承了一个类,无法再继承另一个类。
究竟怎样做才能既可以实现多继承又可以限定类型呢?
关于 LearnKu
一样多重继承啊?
而且,还有抽象类可以用啊。
抽象类实现方法,主体class实现接口。而且,限定为T的理由是什么?想实现什么?确保有t方法可以被调用吗?
说到底还是一个多继承的问题,使用 trait 却不能限定参数类型,不完美
你想要的是接口来限制,而不是用trait。trait只是负责额外的添加方法
trait用法都搞错了,trait是用来解决代码中复用的代码,你要做约束t方法的话,用interface才对,而且你这个想法有点怪异
我的错,没有描述清楚。已更新代码注释为:
确保 t() 可以被调用,于是限定参数类型,但是有问题参考下这个,另外我看你的示例,如果你的t()方法每个子类都是一样的话,那为啥不写在B里面,为啥要搞复杂,弄多继承
说白了,trait 是为了解决部分代码多继承复用的问题,不是用来丰富多态的
参考 PHP: 协变与逆变 - Manual
在以下情况下,类型声明被认为更具体:
问题出在 trait 不能实现接口,如果也能规定 trait 这个问题可能就没有了
感谢大家的回复!1楼已经给出解决方案,就是联合使用接口与 trait 如
class C implements A {use T;}这样的写法。我只是觉得这样的写法比较麻烦,又是接口又是trait的,而且缺一不可。还不如直接去掉类型提示来得简单,例如这样有没办法更新PHP版本,放宽接口的限制,只要接口里面可以直接写函数体,那这个问题就可以轻松解决。如果接口里面可以写函数体,那多继承几乎也就实现了。
或者干脆就实现多继承,那
class Z extends X, Y这样的写法就没问题了我有个想法,不知道能否实现?也就是写一个专门用来处理 trait 类型异常的模块 TraitTypeError 然后在工程开头全局引入这个模块即可。模块逻辑大致如下:
1、匹配异常信息
must be of type T, C given里面的关键字 T 和 C2、使用 ReflectionClass 类获取 C 的代码块;
3、在 C 的代码块搜索关键字
use T,若找到则忽略异常并继续执行代码,否则抛出异常。捕获异常可以用
set_exception_handler('exception_handler')问题是如何忽略这个异常并保证程序继续执行呢?求赐教我只用Triat来复用一些代码,把它看成一个"小型片段库",你用的太高级了,跟不上你们了
换个思路(先抛开 trait):
结论: