使用全局$ config变量是不好的做法吗?

时间:2013-11-26 11:12:35

标签: php configuration global-variables

目前,我使用一个名为$config的变量,它是一个大关联数组,包含应用程序的设置,如文件夹配置,数据库连接,要匹配的URL等等。此变量在其自己的文件system/config.php中定义,该文件包含在主文件system/index.php中。

位于system/request.php的某些系统函数通过global $config;

使用此全局配置变量

这是不好的做法,为什么?什么是处理全局配置的更好方法?

3 个答案:

答案 0 :(得分:0)

恕我直言,只要全局变量不被不同的进程同时修改(即它对所有进程都是只读的),就可以将它放在全局范围内。

模拟只读变量的一种方法是将其封装在一个带有私有变量的全局对象中,以及一个返回该变量的公共方法。

示例:

class Config {
    private $conf = array(/*read from file?*/...);

    function getconf() {
        //AFAIK, any attempt to write into the returned array will make PHP's
        //core to duplicate it, so the original config won't be modified
        //(as long as $conf does not contain objects, which are always addressed
        //by reference)
        return $conf; 
    }
} 

答案 1 :(得分:0)

从任何地方(全局名称空间)引入变量都是不好的,因为您不知道它们如何获得它们的值,并且因为每个类或函数都可以更改它们。因此,除非您使用某种final,const等来保护它们,否则从长远来看它们会破坏系统,并且您将花费数小时来了解它们如何获得其价值。

对于OOP,另一种解决方案是使用容器和依赖项注入。

$container = new Container(array(
    'x' => array(
        'a' => 8,
        'y' => array(
            'b' => 123,
            'z' => 456
        )
    )
));
$x = $container->getX();
$x->doSomething();

如果类之间有很强的耦合性,因为您不希望它们具有一般性,那么您可以这样做:

class Container {

    public function __construct(array $config){
        $this->config = $config;
    }

    public function getX(){
        return new X($this->$config['x']);
    }

}

class X {
    public function __construct(array $config){
        $this->a = $config['a'];
        $this->y = new Y($config['y']);
    }

    public function doSomething(){}
}

class Y {
    public function __construct(array $config){
        $this->b = $config['b'];
        $this->z = new Z($config['z']);
    }
}

class Z {
    public function __construct($number){
        $this->number = $number;
    }
}

如果这些类是松散耦合的,但是您希望将层次结构保留在配置中(例如,因为您的容器中有多个具有不同配置的Y和Z实例),则可以执行以下操作:

class Container {

    public function __construct(array $config){
        $this->config = $config;
    }

    public function getX(){
        return new X($this->$config['x']['a'], $this->getXY());
    }

    public function getXY(){
        return new Y($config['x']['y']['b'], $this->getXYZ());
    }

    public function getXYZ(){
        return new Z($config['x']['y']['z']);
    }

}

class X {
    public function __construct($a, Y $y){
        $this->a = $a;
        $this->y = $y;
    }

    public function doSomething(){}
}

class Y {
    public function __construct($b, Z $z){
        $this->b = $b;
        $this->z = $z
    }
}

class Z {
    public function __construct($number){
        $this->number = $number;
    }
}

即使您不使用OOP进行开发,也应将依赖项作为参数而不是全局变量发送。

function main($config){
    $x = $config['x'];
    $a = $x['a'];
    $y = $x['y'];
    doXSomething($a, $y);
}

function doXSomething($a, array $y){
    $b = $y['b'];
    $z = $y['z'];
    $p = doY($b, $z);
    // ...
}

function doY($b, $z){
    $q = doZ($z);
    // ...
}

function doZ($z){
    // ...
}


$config = array(
    'x' => array(
        'a' => 8,
        'y' => array(
            'b' => 123,
            'z' => 456
        )
    )
);
main($config);

您的代码应仅依赖于局部变量,因此可以确保在应用程序运行时不会从其他函数更改它们。

使用全局变量的另一个不好的原因是可测试性。如果为功能编写测试,则必须设置一个配置变量。如果它是深层嵌套的,则可以执行

$config = array('x' => array('y' => array('z' => 123)))`;
$result = doZ();
expect($result)->toBe(435);

没有全局变量,您可以做

$result = doZ(123);
expect($result)->toBe(435);

根据文件名,我想您早在5年前就有过某种意大利面条式代码。

答案 2 :(得分:0)

As of PHP 7数组常量可以使用define()定义。您可以在常量标量表达式中使用数组,因此请设置$conf值并将其定义为常量

    $conf = ['thekey'=>'the value'];
    define(conf, $conf);

    echo conf['thekey'];