在PHP中停止使用`global’

我有一个config.php包括每个页面。在配置我创建一个数组看起来像:

$config = array();
$config['site_name']      = 'Site Name';
$config['base_path']      = '/home/docs/public_html/';
$config['libraries_path'] = $config['base_path'] . '/libraries';
//etc...

然后我有function.php,也包括几乎每个页面,在那里我必须使用全局$ config来访问它 – 这是我想摆脱!

如何在我的代码的其他部分访问$ config而不使用全局?

有人可以解释,为什么我不应该在我的示例中使用全局?有人说这是一个不好的口气,有人说这不安全?

编辑1:

我在哪里和如何使用它的例子:

function conversion($Exec, $Param = array(), $Log = '') {
        global $config;
        $cmd = $config['phppath'] . ' ' . $config['base_path'] . '/' . $Exec;
                foreach ($Param as $s)
                {
                    $cmd .= ' ' . $s;
                }
 }

编辑2:

把所有这些在类中,如Vilx建议的,会很酷,但在这种情况下,我如何绑定它与从数据库中提取配置键和值的以下循环。我过分简化了赋值$ config数组的想法,这里是一个例子:

$sql = "SELECT * from settings";
$rsc = $db->Execute($sql);
if ( $rsc ) {
    while(!$rsc->EOF) {
        $field = $rsc->fields['setting_options'];
        $config[$field] = $rsc->fields['setting_values'];
        @$rsc->MoveNext();
    }
}

编辑3:

此外,我必须从config中设置的函数访问其他vars,它是少数,例如:$ db,$ language等。

如果我把它们放在类中会真的解决什么吗?如果我使用全局,它真的改变了什么?

编辑4:

我读了PHP global in functions,其中Gordon解释了非常好的方式为什么你不应该使用全局。我同意一切,但我不使用全局在我的情况下重新分配变量,这将导致,像他说,< - WTF !!,;))是同意,它是疯了。但是如果我只需要从一个函数访问数据库只是通过使用全局$ db其中是这种情况下的问题?你如何做到这一点,不使用全局? 编辑5: 在同一个PHP全局函数deceze中说:“反对全局的一个大原因是它意味着函数依赖于另一个范围,这将很快混乱。

但我在这里谈论基本的“INIT”。我基本上设置定义,但使用vars – 这是错误的技术方式。但你的函数不依赖于任何东西 – 但是一个var $ db的名字你可以记住吗?这真的是全球需要使用$ db,在这里的DEPENDENCY和如何使用它否则?

P.S。我只是有一个想法,我们面临着两个不同心理的冲突,例如:我的(但不是很好理解面向对象编程)和那些可以称为大师(从我目前的观点)在OOP – 为他们看起来明显为我出现新的问题。我想这就是为什么这个问题被反复问。对我个人来说,它已经变得更加清楚,但仍然有东西要澄清。

对全局变量的观点是它们非常紧密地耦合代码。您的整个代码库依赖于a)变量名称$ config和b)该变量的存在。如果你想重命名变量(无论什么原因),你必须在整个代码库的任何地方这样做。你也可以不使用依赖于变量的任何代码段。

带全局变量的示例:

require 'SomeClass.php';

$class = new SomeClass;
$class->doSomething();

在上面的任何行,你可能会得到一个错误,因为类或SomeClass.php中的一些代码隐含地依赖于一个全局变量$ config。没有任何迹象表明,虽然只是看着班上。要解决这个问题,你必须这样做:

$config = array(...);

require 'SomeClass.php';

$class = new SomeClass;
$class->doSomething();

如果你没有在$ config里面设置正确的密钥,这个代码可能仍然失败。由于不清楚SomeClass的配置数组的哪些部分需要或不需要,当需要它们时,很难重建正确的环境以使其正确运行。它也创建冲突,如果你碰巧已经有一个变量$ config用于其他地方,无论你想使用SomeClass。

因此,不是创建隐式的,不可见的依赖,注入所有依赖:

require 'SomeClass.php';

$arbitraryConfigVariableName = array(...);

$class = new SomeClass($arbitraryConfigVariableName);
$class->doSomething();

通过将配置数组作为参数显式传递,所有上述问题都解决了。它就像在应用程序内部提交所需的信息一样简单。它还使得应用程序的结构和流程以及什么会话更清楚。要达到这种状态,如果你的应用程序目前是一个大的泥球可能需要一些重组。

你的代码库越大,你必须将各个部分彼此解耦。如果每个部分都依赖于你的代码库中的每一个其他部分,你根本不能单独测试,使用或重用它的任何部分。这只是转化为混乱。为了将部件彼此分离,将它们编码为类或函数,它们将所需的所有数据作为参数。这在代码的不同部分之间创建干净的接口(接口)。

试图把你的问题集中到一个例子:

require_once 'Database.php';
require_once 'ConfigManager.php';
require_once 'Log.php';
require_once 'Foo.php';

// establishes a database connection
$db = new Database('localhost', 'user', 'pass');

// loads the configuration from the database,
// the dependency on the database is explicit without `global`
$configManager = new ConfigManager;
$config = $configManager->loadConfigurationFromDatabase($db);

// creates a new logger which logs to the database,
// note that it reuses the same $db as earlier
$log = new Log($db);

// creates a new Foo instance with explicit configuration passed,
// which was loaded from the database (or anywhere else) earlier
$foo = new Foo($config);

// executes the conversion function, which has access to the configuration
// passed at instantiation time, and also the logger which we created earlier
$foo->conversion('foo', array('bar', 'baz'), $log);

我将把个别课程的实施作为一个练习留给读者。当您尝试实现它们时,您会发现它们非常容易实现,并且不需要单个全局。每个函数和类都以函数参数的形式传递所有必要的数据。还应当显而易见的是,上述组件可以以任何其他组合被插入在一起,或者依赖性可以容易地替代其他组合。例如,配置不需要来自数据库,或者记录器可以记录到文件而不是数据库,没有Foo ::转换必须知道任何这一点。

ConfigManager的示例实现:

class ConfigManager {

    public function loadConfigurationFromDatabase(Database $db) {
        $result = $db->query('SELECT ...');

        $config = array();
        while ($row = $result->fetchRow()) {
            $config[$row['name']] = $row['value'];
        }

        return $config;
    }

}

这是一个非常简单的代码,甚至不做多。你可能会问为什么你想把它作为面向对象的代码。关键是,这使得使用这个代码非常灵活,因为它完全隔离了一切。你给一个数据库连接,你得到一个具有特定语法的数组。输入→输出。清晰的接缝,清晰的界面,最小限度,明确界定的责任。你可以用一个简单的函数做同样的事情。

对象具有的额外优点是,它甚至进一步解耦从该函数的任何特定实现调用loadConfigurationFromDatabase的代码。如果你只是使用一个全局函数loadConfigurationFromDatabase(),你基本上有同样的问题:该函数需要定义,当你尝试调用它,并有命名冲突,如果你要替换它的东西。通过使用对象,代码的关键部分移动到这里:

$config = $configManager->loadConfigurationFromDatabase($db);

你可以用$ configManager这里替换任何其他对象也有一个方法loadConfigurationFromDatabase。这是“鸭式打字”。你不关心$ configManager究竟是什么,只要它有一个方法loadConfigurationFromDatabase。如果它像鸭子一样走路,像鸭子一样尖叫,它是一只鸭子。或者,如果它有一个loadConfigurationFromDatabase方法并返回一个有效的配置数组,它是某种ConfigManager。你已经从一个特定的变量$ config,从一个特定的loadConfigurationFromDatabase函数,甚至从一个特定的ConfigManager解耦你的代码。所有部分都可以更改和交换,并从任何地方进行替换和动态加载,因为代码不依赖于任何一个特定的其他部分。

loadConfigurationFromDatabase方法本身也不依赖于任何一个特定的数据库连接,只要它可以调用查询并获取结果。传递给它的$ db对象可以是完全假的,并且从XML文件或任何其他地方读取它的数据,只要它的接口仍然表现相同。

http://stackoverflow.com/questions/12445972/stop-using-global-in-php

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:在PHP中停止使用`global’