Как проверить, является ли функция общедоступной или защищенной в PHP
Я создаю API, где пользователь запрашивает "команду", которая передается в класс. Предполагая, что команда соответствует функции PUBLIC, она будет выполнена успешно.
Если команда соответствует функции PROTECTED, ей необходимо выдать ошибку.
Идея состоит в том, что функции можно отключить, изменив их с PUBLIC на PROTECTED, вместо того, чтобы переименовывать их или удалять.
В настоящее время я делаю это, но неважно, является ли команда общедоступной или защищенной.
<?php
/**
* Look for Command method
*/
$sMethod = "{$sCommand}Command";
if (method_exists($this, $sMethod))
{
/**
* Run the command
*/
return $this->$sMethod($aParameters);
}
Ответы
Ответ 1
Просто используйте ReflectionMethod:
/**
* Look for Command method
*/
if (method_exists($this, $sMethod))
{
$reflection = new ReflectionMethod($this, $sMethod);
if (!$reflection->isPublic()) {
throw new RuntimeException("The called method is not public.");
}
/**
* Run the command
*/
return $this->$sMethod($aParameters);
}
Ответ 2
Вы можете использовать функцию is_callable, чтобы определить, должен ли уровень защиты ограничивать вас: Пример:
<?php
class FooBar {
protected function Foo() { return; }
public function Bar() { return; }
}
$foo = new FooBar();
var_dump(is_callable(array($foo, 'Foo')));
var_dump(is_callable(array($foo, 'Bar')));
Ответ 3
Хотя вы не можете отличить, является ли метод приватным или защищенным, вы можете проверить, существует ли public или нет внешнего метода, используя is_callable
. Я сделал сравнение с ответом "Мезе".
Итак:
function testIfCallable($object, $method) {
return is_callable(array($object, $method));
}
function testIfCallable2($object, $method) {
if (method_exists($object, $method))
{
$reflection = new ReflectionMethod($object, $method);
return $reflection->isPublic();
}
return false;
}
class Test {
private function privateMethod() {
}
protected function protectedMethod() {
}
public function publicMethod() {
}
public function testAccessibility() {
if (testIfCallable($this, 'privateMethod')) echo "YYY<br>"; else echo 'NNN<br>';
if (testIfCallable($this, 'protectedMethod')) echo "YYY<br>"; else echo 'NNN<br>';
if (testIfCallable($this, 'publicMethod')) echo "YYY<br>"; else echo 'NNN<br>';
}
public function testAccessibility2() {
if (testIfCallable2($this, 'privateMethod')) echo "YYY<br>"; else echo 'NNN<br>';
if (testIfCallable2($this, 'protectedMethod')) echo "YYY<br>"; else echo 'NNN<br>';
if (testIfCallable2($this, 'publicMethod')) echo "YYY<br>"; else echo 'NNN<br>';
}
public function testSpeedAccessibility() {
return $results = [
testIfCallable($this, 'privateMethod'),
testIfCallable($this, 'protectedMethod'),
testIfCallable($this, 'publicMethod')
];
}
public function testSpeedAccesibility2() {
return $results = [
testIfCallable2($this, 'privateMethod'),
testIfCallable2($this, 'protectedMethod'),
testIfCallable2($this, 'publicMethod')
];
}
}
Метод testIfCallable
должен быть включен в общий класс или что-то подобное, что у вас есть в вашем собственном наборе инструментов, поскольку глобальные методы не рекомендуются.
Я использую это в сочетании с магическими методами __get
и __set
, чтобы обеспечить общедоступный метод get/set.
Тесты:
//Test functionality
$t = new Test();
$t->testAccessibility();
$t->testAccessibility2();
//Test speed
$start = microtime(true);
for($i = 0; $i < 10000; $i++) {
$t->testSpeedAccessibility();
}
echo "Is Callable way: " . (microtime(true) - $start) . "ms<br>";
$start = microtime(true);
for($i = 0; $i < 10000; $i++) {
$t->testSpeedAccesibility2();
}
echo "Reflection way: " . (microtime(true) - $start) . "ms<br>";
Выходы:
NNN
NNN
YYY
NNN
NNN
YYY
Is Callable way: 0.23506498336792ms
Reflection way: 0.45829010009766ms
Заключительные мысли
Если вам нужно протестировать все возможности видимости, вы можете использовать только testIfCallable2
, поэтому ответ "meze". В противном случае мой путь примерно в два раза быстрее. Поскольку ваш вопрос был только между публикой или нет, вы могли бы воспользоваться этим. Говоря, что, если вы не используете его часто, разница не имеет значения.