使用__get或类似方法访问Array类型的类成员变量


Accessing a class member variable of type Array using __get or similar

以前我正在重建的一个类有一个成员变量$settings,这是一个设置数组,这很奇怪。

class MyClass {
    public $settings = array();
    public function __construct() {
        if( empty( $this->settings ) ) {
            $this->settings = require( 'settings.php' ); // e.g. return array('setting1'=>4);
        }
    }
}

$object->settings['keyname']; 访问了这些设置

访问这些密钥的方式现在已经转变为一种方法。然而,应用程序本身充斥着对$object->settings['keyname']的调用。我想知道有没有一种方法可以捕获对$settings成员变量的任何调用,并使用新函数返回它。

我看过__get($name),但$name只包含settings,而不是我需要的数组密钥。我需要传递的是我的$object->get()方法的keyname。

我之所以要这样做,是因为我可以在日志文件中触发错误,显示对$object->settings[]的不推荐调用的位置,而不会破坏应用程序。显然,将$setting设置为private会给我带来很多致命的错误,我可以解决这些错误,但有多个开发人员在开发这个代码库,我不希望破坏它。如果我能把它作为一个临时解决方案来实现,它会有所帮助。

我意识到我们可以使用一些存储库等,这样我就可以单独处理它,然后再检查它,但我正在寻找一个快速、临时的解决方案,因为我们正在将代码库移植到Git soonish。

完全可能:

<?php
class Logger {
    public function log( $name, $backtrace ) {
        /**
         * $name is the name of the array index that was called on
         * MyClass->settings( ). $backtrace contains an array in which
         * you can find and determine which file has accessed that index,
         * and on which line.
         */
        $last = array_shift( $backtrace );
        $message = sprintf( "Setting '%s' was called by file '%s' on line %d",
            $name,
            $last['file'],
            $last['line']
        );
        echo $message;  
    }
}
class MyClass {
    protected $settings;
    public function __construct( ) {
        $this->settings = new Settings( new Logger( ), array( 'foo' => 'bar' ) );
    }
    public function __get( $name ) {
        if( $name === 'settings' ) {
            return $this->settings;
        }
    }
}
class Settings extends ArrayObject {
    protected $logger;
    protected $settings;
    public function __construct( Logger $logger, array $settings ) {
        $this->logger = $logger;
        parent::__construct( $settings );
    }
    public function offsetGet( $name ) {
        $backtrace = debug_backtrace( );
        $this->logger->log( $name, $backtrace );
        return parent::offsetGet( $name );
    }
}
$myClass = new MyClass( );
echo $myClass->settings['foo'] . "'n";

当然,它很有技巧,你可能不想把它保存在你的代码库中,但对于记录不推荐的使用,它可能会非常有用。只需登录一段时间,然后用$this->settings = array( )替换$this->settings = new Settings( )

顺便说一下,这个确切代码的输出如下:

berry@berry-pc:~/Desktop% php foo.php
Setting 'foo' was called by file '/home/berry/Desktop/foo.php' on line 53
bar

要查找脚本在设置中设置变量的位置:

我建议在MyClass类的构造函数和析构函数中放入一个小的肮脏破解。在构造函数中,扫描$settings并检查是否存在不推荐使用的值(将其保存在临时位置)。在析构函数中执行相同的检查,并交叉匹配这两个结果。当你在销毁过程中有新的变量时,你就知道$_SERVER['PHP_SELF']已经设置了它

要查找脚本访问它的位置:

粗鲁,但我建议将所有不推荐使用的值转换为新值,然后看着事情停止工作。与修改类以使用记录器

相比,您将花费更少的时间来跟踪故障原因,并阅读"This used to work and not"投诉