gpt4 book ai didi

php - 停止在 PHP 中使用 `global`

转载 作者:IT王子 更新时间:2023-10-29 00:53:43 24 4
gpt4 key购买 nike

我有一个 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 ,这也包含在几乎每个页面中,我必须使用 global $config访问它 - 这就是我想要摆脱的!
我如何访问 $config在我代码的其他部分不使用 global ?
谁能解释一下, 为什么我不应该使用 global在我的例子中?有人说这是一种不好的语气,有人说它不安全?
编辑 1:
我在哪里以及如何使用它的示例:
function conversion($Exec, $Param = array(), $Log = '') {
global $config;
$cmd = $config['phppath'] . ' ' . $config['base_path'] . '/' . $Exec;
foreach ($Param as $s)
{
$cmd .= ' ' . $s;
}
}
编辑2:
正如 Vilx 所建议的那样,将所有这些都放在类里面, 会很酷,但在这种情况下,我如何将它与以下提取配置的循环联系起来 keyvalue从数据库。我过度简化了分配 $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:
此外,我必须访问其他 vars来自 config 中设置的函数,而且很少,例如: $db , $language等等。
如果我把它们放在类里面,它真的能解决任何问题吗?如果我使用 global它真正改变了什么?
编辑 4:
我读了 PHP global in functions哪里 Gordon以非常好的方式解释了为什么你不应该使用 global .我同意一切,但我不使用 global在我的情况下,重新分配变量,这将导致,就像他说的, <-- WTF!! , ;)) 是的,同意,这太疯狂了。但是如果我只需要使用 global $db 从函数访问数据库在这种情况下问题出在哪里?在不使用 global 的情况下,您如何做到这一点? ?
编辑 5:
在相同的 PHP 全局函数中 deceze说:“反对 global 的一个重要原因是它意味着该函数依赖于另一个作用域。这会很快变得困惑。”
但我在这里谈论的是基本的“INIT”。我基本设置了 define但使用 vars - 好吧,这在技术上是错误的。但是你的函数不依赖于任何东西——而是一个 var 的名称 $db你能记住吗?全局需要使用 $db ,这里的依赖在哪里以及如何使用它?
附言我只是有一个想法,我们在这里面临着两种不同思想的冲突,例如:我的(但不太了解面向对象编程)和那些在 OOP 中可以被称为大师(从我目前的角度来看)的人 -对我来说看起来很明显的东西会出现新的问题。我认为这就是为什么一遍又一遍地问这个问题的原因。就我个人而言,它毕竟变得更加清晰,但仍有一些事情需要澄清。

最佳答案

点对点global变量是它们非常紧密地耦合代码。您的整个代码库取决于 a) 变量名称 $config b) 该变量的存在。如果您想重命名变量(无论出于何种原因),您必须在整个代码库中的任何地方都这样做。您也不能再使用任何依赖于变量的代码。

示例与 global多变的:

require 'SomeClass.php';

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

在上面几行的任何地方你都可能得到一个错误,因为 SomeClass.php 中的类或一些代码隐式依赖于一个全局变量 $config .尽管只是看类(class),但没有任何迹象表明这一点。要解决这个问题,你必须这样做:
$config = array(...);

require 'SomeClass.php';

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

如果您没有在 $config 中设置正确的 key ,此代码可能仍会在某处失败。 .由于配置数组的哪些部分并不明显 SomeClass需要或不需要,当它需要它们时,很难重新创建正确的环境以使其正确运行。如果您碰巧已经有一个变量 $config,它也会产生冲突。用于其他任何你想使用的地方 SomeClass .

因此,不要创建隐式的、不可见的依赖项,而是注入(inject)所有依赖项:
require 'SomeClass.php';

$arbitraryConfigVariableName = array(...);

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

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

您的代码库越大,您就越需要将各个部分彼此分离。如果每个部分都依赖于代码库中的所有其他部分,则您根本无法单独测试、使用或重用它的任何部分。那只会陷入困惑。要将部分彼此分开,请将它们编码为类或函数,这些类或函数将所有必需的数据作为参数。这会在代码的不同部分之间创建干净的接缝(接口(interface))。

试图将您的问题合并为一个示例:
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);

我将把各个类的实现留给读者作为练习。当您尝试实现它们时,您会注意到它们实现起来非常简单明了,并且不需要一个 global .每个函数和类都获得以函数参数形式传递的所有必要数据。很明显,上述组件可以以任何其他组合插入在一起,或者依赖项可以很容易地替换为其他组件。例如,配置根本不需要来自数据库,或者记录器可以在没有 Foo::conversion的情况下记录到文件而不是数据库。必须知道这些。
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;
}

}

这是一段非常简单的代码,甚至没有做太多事情。您可能会问为什么要将其作为面向对象的代码。关键是这使得使用此代码非常灵活,因为它将它与其他任何东西完美地隔离开来。你输入一个数据库连接,你得到一个具有特定语法的数组。输入 → 输出。清晰的接缝、清晰的接口(interface)、最小的、明确定义的职责。你可以用一个简单的函数来做同样的事情。

对象的额外优势是它甚至进一步解耦了调用 loadConfigurationFromDatabase 的代码。来自该功能的任何特定实现。如果您只是使用全局 function loadConfigurationFromDatabase() ,你基本上又遇到了同样的问题:当你尝试调用它时需要定义该函数,如果你想用其他东西替换它,就会存在命名冲突。通过使用对象,代码的关键部分移到这里:
$config = $configManager->loadConfigurationFromDatabase($db);

您可以替换 $configManager此处用于任何其他也具有方法的对象 loadConfigurationFromDatabase .那就是“鸭子打字”。你不在乎究竟是什么 $configManager就是,只要它有方法 loadConfigurationFromDatabase .如果它走路像鸭子,叫起来像鸭子,那就是鸭子。或者更确切地说,如果它有 loadConfigurationFromDatabase方法并返回一个有效的配置数组,它是某种 ConfigManager。您已将代码与一个特定变量 $config 分离,来自一个特定的 loadConfigurationFromDatabase功能,甚至来自一个特定的 ConfigManager .所有部分都可以从任何地方动态更改和换出、替换和加载,因为代码不依赖于任何一个特定的其他部分。
loadConfigurationFromDatabase方法本身也不依赖于任何一个特定的数据库连接,只要它可以调用 query在它上面并获取结果。 $db传递给它的对象可能完全是假的,并且可以从 XML 文件或其他任何地方读取其数据,只要其接口(interface)的行为仍然相同。

关于php - 停止在 PHP 中使用 `global`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12445972/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com