【问题标题】:php get visibilityphp获取可见性
【发布时间】:2011-06-10 10:09:10
【问题描述】:

是否可以在php中获取类中方法和属性的可见性?

我希望能够做这样的事情:

function __call($method, $args)
{
    if(is_callable(array($this,$method))
    {
        if(get_visibility(array($this,$method)) == 'private')
            //dosomething
        elseif(get_visibility(array($this,$method)) == 'protected')
            //dosomething
        else
            //dosomething
    } 
} 

【问题讨论】:

  • 如果你使用反射可能是可行的,但我不能保证性能。我也想不出你需要能够做到这一点的任何情况。也许您最好考虑一下为什么要这样做,以及是否真的有必要。你不想让你不需要的复杂性和魔法把你的代码弄得乱七八糟。
  • 了解可见性的一个用例是,如果您在实现魔术方法__get() 时尝试模拟内置 PHP 错误的精度。

标签: php visibility access-modifiers


【解决方案1】:

这个答案有点晚了,但我觉得get_class_methods()结合method_exists(),我觉得还是有一些附加价值的:

<?php
class Foo {
    // ...
    public function getVisibility($method) {
        if ( method_exists($this, $method) && in_array($method, get_class_methods($this)) ) {
            return 'protected or public';
        } else {
            return 'private';
        }
    }
}

【讨论】:

    【解决方案2】:

    is_callable 考虑了可见性,但由于您是在类内部使用它,所以它总是评估为TRUE

    要获得方法可见性,您必须use the Reflection API and check the method's modifiers

    PHP 手册中的节略示例:

    class Testing
    {
        final public static function foo()
        {
            return;
        }
    }
    
    // this would go into your __call method
    $foo = new ReflectionMethod('Testing', 'foo');
    echo implode(
        Reflection::getModifierNames(
            $foo->getModifiers()
        )
    ); // outputs finalpublicstatic
    

    同样适用于properties

    但是,由于反射类的复杂性,这可能会很慢。您应该对其进行基准测试,看看它是否对您的应用程序影响太大。

    【讨论】:

    • 我刚刚做了一个快速基准测试,似乎检查一个方法是否具有一定的可见性然后调用该方法比直接调用该方法慢大约 3 倍。对于大型方法,这可以忽略不计,但对于较小的方法(或属性),这不是。
    • @Tiddo 考虑到首先使用__call__get 已经很慢了。因此,除非您的基准列出了单个函数调用,否则您对结果的解释可能是错误的。在旁注中,您最好通过接口和组合/聚合以及策略和装饰器来解决多重继承。
    • 我知道,但是我在没有 __call 或 __get 方法的情况下对其进行了测试:我从类外部调用了一个函数几百次,有和没有修饰符检查。我知道我最好通过接口等来解决这些问题,但在某些情况下,使用多重继承解决这些问题要容易得多。
    【解决方案3】:

    您可能需要考虑为此使用 PHP 的 Reflection API。但是,我也应该问你为什么你想这样做,因为反射通常只在开始时有点笨拙的情况下使用。不过这是可能的,所以这里是:

    <?php
    
    class Foo {
        /**
         *
         * @var ReflectionClass
         */
        protected $reflection;
        protected function bar( ) {
    
        }
    
        private function baz( ) {
    
        }
    
        public function __call( $method, $args ) {
            if( ( $reflMethod = $this->method( $method ) ) !== false ) {
                if( $reflMethod->isPrivate( ) ) {
                    echo "That's private.<br />\n";
                }
                elseif( $reflMethod->isProtected( ) ) {
                    echo "That's protected.<br />\n";
                }
            }
        }
    
        protected function method( $name ) {
            if( !isset( $this->methods[$name] ) ) {
                if( $this->reflect( )->hasMethod( $name ) ) {
                    $this->methods[$name] = $this->reflect( )->getMethod( $name );
                }
                else {
                    $this->methods[$name] = false;
                }
            }
            return $this->methods[$name];
        }
    
        protected function reflect( ) {
            if( !isset( $this->reflection ) ) {
                $this->reflection = new ReflectionClass( $this );
            }
            return $this->reflection;
        }
    }
    
    $foo = new Foo( );
    $foo->baz( );
    $foo->bar( );
    

    【讨论】:

    • 我想这样做是因为我只是在尝试在 php 中模拟多重继承。但是要获得完整的功能,我需要能够区分私有方法和受保护方法。题外话:真巧,我们都是荷兰人,姓氏一样
    • 哈,真是巧合。您是否阅读过关于 PHP 中水平重用的 RFC,该 RFC 不久前已提交到主干?如果没有,请在此处查看; wiki.php.net/rfc/traits
    • 我已经读过了。我希望它会出现在 PHP 的下一个版本中,但我不得不说,对我来说,它似乎只是方法的多重继承,所以我真的不明白为什么这比 mi. (例如,您仍然需要手动解决钻石问题)
    • +1 回答了这个问题,尽管您认为发帖人的所作所为可能是个坏主意。
    • @tiddo 多重继承是一个错误功能,而且很少有 OO 语言支持它是有充分理由的。您可以使用 PHP 特征和接口来完成类似的功能,但我从来没有这样做过,而且我认为特征也是一种错误功能。
    猜你喜欢
    • 1970-01-01
    • 2010-11-20
    • 1970-01-01
    • 2012-08-01
    • 2010-09-18
    • 2015-10-18
    • 1970-01-01
    • 2012-10-14
    • 2011-07-17
    相关资源
    最近更新 更多