代码之家  ›  专栏  ›  技术社区  ›  Stephen RC

如何检查函数在PHP中是公共的还是受保护的

php
  •  26
  • Stephen RC  · 技术社区  · 15 年前

    我正在构建一个API,其中用户请求一个“命令”,它被传递到一个类中。假设命令与公共函数匹配,它将成功执行。 如果命令与受保护的函数匹配,则需要抛出一个错误。

    其思想是,可以通过将函数从public更改为protected来禁用函数,而不是重命名或删除它们。

    我现在这样做,但是命令是公开的还是受保护的并不重要。

    <?php
    /**
     * Look for Command method
     */
    $sMethod = "{$sCommand}Command";
    if (method_exists($this, $sMethod))
    {
        /**
         * Run the command
         */
        return $this->$sMethod($aParameters);
    }
    
    3 回复  |  直到 15 年前
        1
  •  56
  •   meze    15 年前

    简单使用 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
  •  9
  •   rhollencamp    15 年前

    您可以使用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
  •  1
  •   Master DJon    9 年前

    虽然不能区分方法是私有的还是受保护的,但是可以使用 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 所以“梅兹”的答案。否则,我的路会快两倍。因为你的问题只是在公众和非公众之间,所以你可以从中受益。这么说,如果你不经常使用它,区别就不显著了。

    推荐文章