Как проверить, является ли функция общедоступной или защищенной в PHP
Я строю API, где пользователь запрашивает "команду", которая передается в класс. Предполагая, что команда соответствует функции PUBLIC, она будет выполнена успешно. Если команда соответствует ЗАЩИЩЕННОЙ функции, она должна выдать ошибку.
Идея заключается в том, что функции можно отключить, изменив их с ОБЩЕГО на ЗАЩИЩЕННЫЕ, а не переименовывая или удаляя их.
В настоящее время я делаю это, но не имеет значения, является ли команда общедоступной или защищенной.
<?php
/**
* Look for Command method
*/
$sMethod = "{$sCommand}Command";
if (method_exists($this, $sMethod))
{
/**
* Run the command
*/
return $this->$sMethod($aParameters);
}
3 ответа
Просто используйте 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);
}
Вы можете использовать функцию 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')));
Хотя вы не можете различить, является ли метод закрытым или защищенным, вы можете проверить, является ли метод общедоступным, а не использовать внешний метод, используя 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
должны быть включены в класс Common или что-то подобное, что есть в вашем собственном наборе инструментов, потому что глобальные методы не рекомендуются.
Я использую это в сочетании с магическими методами __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
так что ответ "мезе". В противном случае мой путь примерно в два раза быстрее. Поскольку ваш вопрос был только между публикой или нет, вы могли бы извлечь выгоду, используя это. Сказать, что, если вы не используете его часто, разница не значительна.