Reputation: 633
What I want to get is the array of all public methods, and ONLY public ones, from the lowest classes in the inheritance tree. For example:
class MyClass { }
class MyExtendedClass extends MyClass { }
class SomeOtherClass extends MyClass { }
And from the inside of MyClass I want to get all PUBLIC methods from MyExtendedClass and SomeOtherClass.
I figured out I can use Reflection Class to do this, however when I do that, I also get methods from the MyClass, and I don't want to get them:
$class = new ReflectionClass('MyClass');
$methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);
Is there a way to do this? Or the only solution I have in this situation is just to filter out the outcomes of the Reflection Class?
Upvotes: 18
Views: 12025
Reputation: 1608
You can compare getDeclaringClass
against static::class
. For example in base class you can declare one helper method like following
final public function events()
{
return array_reduce(
(new ReflectionClass($this))->getMethods(ReflectionMethod::IS_PUBLIC),
function (array $carry, ReflectionMethod $method) {
if ($method->getDeclaringClass()->name === static::class) {
array_push($carry, $method->getName());
}
return $carry;
},
[]
);
}
Upvotes: 0
Reputation: 3806
No, I don't think you can filter out the parent methods at once. But it'd be quite simple to just filter the results by the class index.
$methods = [];
foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method)
if ($method['class'] == $reflection->getName())
$methods[] = $method['name'];
Upvotes: 23
Reputation: 964
I had the need to do the same and came up with the following function:
function getMethods($class, $visibility = "")
{
$reflect = new ReflectionClass($class);
$methods = [];
// Iterate the methods
foreach ($reflect->getMethods() as $value){
/*
* $value->getFileName() returns actual file name a method was set in.
* if it does not match the current filename it is a inherited method assuming a file contains only one class
*/
if ($value->getFileName() == $reflect->getFileName()) {
if ($value->isPublic() === true) {
$methods['public'][] = $value->name;
}
elseif ($value->isPrivate() === true) {
$methods['private'][] = $value->name;
}
elseif ($value->isProtected() === true) {
$methods['protected'][] = $value->name;
}
}
}
switch ($visibility) {
case "private":
case "public":
case "protected":
return $methods[$visibility];
break;
default:
return $methods;
break;
}
}
Using the following test code in Father.php and Child.php
class Father{
public function parentTest() { }
}
class Child extends Father {
public function __construct() { }
private function test() { }
protected function test2() { }
}
Which returns the following:
array (size=3)
'public' =>
array (size=1)
0 => string '__construct' (length=11)
'private' =>
array (size=1)
0 => string 'test' (length=4)
'protected' =>
array (size=1)
0 => string 'test2' (length=5)
Upvotes: 1
Reputation: 5208
I just wrote a method with some extra functionality that expands on Daniel's answer.
It allows you to return static or object methods only.
It also allows you to only return methods that have been defined in that class.
Supply your own namespace or just copy the method.
Example Usage:
$methods = Reflection::getClassMethods(__CLASS__);
Code:
<?php
namespace [Your]\[Namespace];
class Reflection {
/**
* Return class methods by scope
*
* @param string $class
* @param bool $inherit
* @static bool|null $static returns static methods | object methods | both
* @param array $scope ['public', 'protected', 'private']
* @return array
*/
public static function getClassMethods($class, $inherit = false, $static = null, $scope = ['public', 'protected', 'private'])
{
$return = [
'public' => [],
'protected' => [],
'private' => []
];
$reflection = new \ReflectionClass($class);
foreach ($scope as $key) {
$pass = false;
switch ($key) {
case 'public': $pass = \ReflectionMethod::IS_PUBLIC;
break;
case 'protected': $pass = \ReflectionMethod::IS_PROTECTED;
break;
case 'private': $pass = \ReflectionMethod::IS_PRIVATE;
break;
}
if ($pass) {
$methods = $reflection->getMethods($pass);
foreach ($methods as $method) {
$isStatic = $method->isStatic();
if (!is_null($static) && $static && !$isStatic) {
continue;
} elseif (!is_null($static) && !$static && $isStatic) {
continue;
}
if (!$inherit && $method->class === $reflection->getName()) {
$return[$key][] = $method->name;
} elseif ($inherit) {
$return[$key][] = $method->name;
}
}
}
}
return $return;
}
}
Upvotes: 4