我正在尝试在重写特质方法的类中生成方法数组。这是一个简化的示例,显示了我的应用中典型类和特征的方法的结构:
class demo
{
public function MethodA()
{
return 'method A from class';
}
public function MethodC()
{
return 'method C from class';
}
public function MethodE()
{
return 'method E from class';
}
use tGeneric;
}
trait tGeneric
{
public function MethodA()
{
return 'method A from trait';
}
public function MethodB()
{
return 'method B from trait';
}
public function MethodD()
{
return 'method D from trait';
}
public function MethodE()
{
return 'method E from trait';
}
}
根据PHP manual中列出的优先级规则:
优先顺序是当前类中的方法会覆盖Trait方法,而Trait方法又会覆盖基类中的方法。
这表现出预期,因为此代码的输出:
$object = new demo();
$array = [
$object->MethodA(),
$object->MethodB(),
$object->MethodC(),
$object->MethodD(),
$object->MethodE()
];
$br = '<br>';
$msg = '';
foreach ($array as $value):
$msg .= $value . $br;
endforeach;
echo $msg . $br;
类demo
中重写tGeneric
中特征方法的方法是MethodA()和MethodE()。有没有一种方法可以通过编程方式在类中仅生成这些方法的数组,以覆盖特征中的方法?
我已经尝试了反射,但是GetMethods()
方法检索了一个类的所有方法,无论它们是起源于类还是通过使用特征获取的。
此代码:
$rc = new ReflectionClass('demo');
$d = $rc->GetMethods();
$traits = class_uses('demo');
foreach ($traits as $trait):
$reflection = new ReflectionClass($trait);
$t = $reflection->GetMethods();
endforeach;
DisplayInfo($d);
DisplayInfo($t);
function DisplayInfo($array)
{
$br = '<br>';
echo '<b>' . $array[0]->class . '</b>' . $br;
foreach ($array as $value):
echo $value->name . $br;
endforeach;
echo $br;
}
答案 0 :(得分:2)
通过比较,您可以确保几乎确保方法覆盖特征方法:
if ($class_method->getFileName() !== $trait_method->getFileName()
|| $class_method->getStartLine() !== $trait_method->getStartLine()) {
$methods_overridden[] = $class_method->getName();
}
(当然,它们也需要使用相同的名称)
/**
* Given a class name, retrieves the corresponding class' methods that override
* trait methods.
*
* @param string $class_name
* @return \ReflectionMethod[]
* @throws \ReflectionException
*/
function getMethodsOverriddenFromTraits(string $class_name): array
{
$class = new \ReflectionClass($class_name);
// Retrieve trait methods
$trait_methods = [];
foreach ($class->getTraits() as $trait) {
foreach ($trait->getMethods() as $trait_method) {
$trait_methods[$trait_method->getName()] = $trait_method;
}
}
// Compute class methods that override them
$methods_overridden = [];
foreach ($class->getMethods() as $class_method) {
if (array_key_exists($class_method->getName(), $trait_methods)) {
$trait_method = $trait_methods[$class_method->getName()];
if ($class_method->getFileName() !== $trait_method->getFileName()
|| $class_method->getStartLine() !== $trait_method->getStartLine()) {
$methods_overridden[] = $class_method->getName();
}
}
}
return $methods_overridden;
}
答案 1 :(得分:1)
如果这是一个更真实的代码场景,其中特征和类在单个文件中,那么这是一种可能的解决方案,它应该是您无论如何进行编码(IMHO)...
因此,我将特征代码存储在文件中(我将其称为TraitTest.php)。然后,在我的主脚本中是剩下的代码,但是当然要使用require_once 'TraitTest.php';
。然后在DisplayInfo()
函数中,我刚刚添加了getFileName()
的值,该值显示了定义方法的文件名...
function DisplayInfo($array)
{
$br = PHP_EOL;
echo '<b>' . $array[0]->class . '</b>' . $br;
foreach ($array as $value) {
echo $value->getFileName()."->".$value->name . $br;
}
echo $br;
}
显示...
<b>demo</b>
/home/nigel/workspace2/Test/t1.php->MethodA
/home/nigel/workspace2/Test/t1.php->MethodC
/home/nigel/workspace2/Test/t1.php->MethodE
/home/nigel/workspace2/Test/TraitTest.php->MethodB
/home/nigel/workspace2/Test/TraitTest.php->MethodD
<b>TraitTest</b>
/home/nigel/workspace2/Test/TraitTest.php->MethodA
/home/nigel/workspace2/Test/TraitTest.php->MethodB
/home/nigel/workspace2/Test/TraitTest.php->MethodD
/home/nigel/workspace2/Test/TraitTest.php->MethodE
如您所见,MethodB
显示为在TraitTest.php
中定义。