我有一个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
在示例中使用?有人说这是一个不好的语气,有人说这是不安全的?
我在哪里以及如何使用它的示例:
function conversion($Exec, $Param = array(), $Log = '') {
global $config;
$cmd = $config['phppath'] . ' ' . $config['base_path'] . '/' . $Exec;
foreach ($Param as $s)
{
$cmd .= ' ' . $s;
}
}
按照Vilx的建议,将所有这些内容放入类中会很酷,但是在这种情况下,我如何将其与以下从配置中提取key
并value
从数据库中提取的循环联系起来。
我简化了分配$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();
}
}
此外,我还必须vars
从config中设置的功能访问其他内容,例如:$db
,$language
等。
如果我将它们放在班上,真的可以解决什么问题?如果我使用global
,它将真正改变什么?
我在函数中读过PHP global,其中Gordon很好地解释了为什么不应该使用global
。我对所有事情都表示同意,但是global
在我的案例中,我不使用它来重新分配变量,这将导致如他所说的<-- WTF!!
;,))是的,这很疯狂。但是,如果我只需要通过使用函数访问数据库,global $db
在这种情况下,问题出在哪里?不使用该怎么办global
?
deceze在同一PHP全局函数中表示:
“反对global的一个重要原因是,这意味着该函数依赖于另一个作用域。这将很快变得混乱。”
但是我在这里谈论的是基本的“ INIT”。我基本上设置define
但使用vars
-嗯,这在技术上是错误的。但是您的函数不依赖于任何东西-
而是$db
您可以记住的一个var的名称?这确实是全球性的需求$db
,这里的依赖关系在哪里,否则如何使用?
PS 我只是有一个想法,我们在这里面临着两种不同思想的冲突,例如: 我的
(但还不太了解面向对象的编程)和那些在OOP中可以称为大师的人(从我当前的观点来看)
-对我来说对他们来说显而易见的是新的问题。我认为这就是为什么一遍又一遍地问这个问题的原因。就我个人而言,它已经变得更加清晰了,但是仍然有一些事情需要澄清。
反对global
变量的重点是它们非常紧密地耦合代码。您的 整个代码库 取决于a)变量 名称
$config
和b)该变量的存在。如果要重命名变量(无论出于何种原因),则必须 在 整个代码库中的 任何地方
进行重命名。您也不能再使用任何依赖于变量的代码了。
带有global
变量的示例:
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();
通过显式传递config数组作为参数,可以解决上述所有问题。这就像在应用程序内部 分发所需的信息
一样简单。它还使应用程序的结构和流程以及讨论的内容变得更加清晰。要达到这种状态(如果您的应用程序当前是一个大问题),可能需要进行一些重组。
您的代码库越大,则您越需要 将 各个部分彼此 分离
。如果每个部分都依赖于代码库中的每个其他部分,则您根本无法单独测试,使用或重用它的任何部分。那简直变成混乱。为了将各个部分彼此分开,请将它们编码为类或函数,这些类或函数将其所有必需数据作为参数。这就在代码的不同部分之间创建了清晰的接缝(接口)。
尝试将您的问题归纳为一个示例:
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;
}
}
这是一段非常简单的代码,甚至没有做很多事情。您可能会问为什么要将此作为面向对象的代码。关键是,这使该代码的使用极为灵活,因为它可以将其与其他所有代码完美地隔离开来。输入一个数据库连接,返回一个具有特定语法的数组。输入→输出。清晰的接缝,清晰的界面,最少的,明确定义的职责。您可以使用简单的功能执行相同的操作。
对象具有的额外优点是,它甚至可以进一步将调用的代码loadConfigurationFromDatabase
与该函数的任何特定实现分离。如果仅使用global
function loadConfigurationFromDatabase()
,则基本上还会遇到相同的问题:尝试调用该函数时需要定义该函数,如果要用其他函数替换它,则存在命名冲突。通过使用对象,代码的关键部分移至此处:
$config = $configManager->loadConfigurationFromDatabase($db);
您可以$configManager
在这里替换同样具有method的
任何其他对象loadConfigurationFromDatabase
。那就是“鸭子打字”。$configManager
只要它有一个方法,您都不关心它到底是什么loadConfigurationFromDatabase
。如果它走路像鸭子,而嘎嘎叫鸭子,那它就是鸭子。或者说,如果它有一个loadConfigurationFromDatabase
方法并返回有效的配置数组,则它是某种ConfigManager。您已将代码与一个特定变量$config
,一个特定loadConfigurationFromDatabase
函数甚至一个特定变量解耦ConfigManager
。可以从任何地方动态更改和替换所有零件,并进行替换和加载,因为代码不依赖于任何其他特定零件。
该loadConfigurationFromDatabase
方法本身也不依赖于任何一个特定的数据库连接,只要它可以调用query
它并获取结果即可。该$db
对象被传递到它可能是完全伪造的,并从XML文件中读取其数据或其他地方代替,只要它的
界面 仍然表现相同。
我有一个包含到每个页面。在配置中,我创建了一个类似于以下内容的数组: 然后我有,它也包含在几乎每个页面中,在那里我必须使用来访问它-这就是我想要摆脱的! 如何在不使用的情况下访问代码的其他部分? 谁能解释一下,为什么我不应该在我的示例中使用?有人说这是一个坏的语气,其他人说这是不安全的? 我在哪里以及如何使用它的示例: 按照Vilx的建议,将所有这些都放在类中会很酷,但在这种情况下,我将如何将其与
问题内容: 如果我在命令行中键入,则可以看到以下行: 要 启动 此cronjob,我需要使用命令编辑文件,删除该行开头的注释字符,保存已编辑的文件,然后退出编辑器。 要 停止 此cronjob,请执行相同的步骤,但在该行的开头添加注释字符。 我想使用 PHP脚本 实现完全相同的效果,而不是手动编辑文件。 问题答案: 我进行了一些研究,并在论坛中找到以下消息: 将EDITOR环境变量设置为php脚本
问题内容: 在装有PHP 5.5.3的新Macbook上安装MAMP。 重新加载和刷新无济于事。依然没有。Google过了几分钟,试图找出问题所在,然后回来刷新。有用。有没有搞错? 我进入php.ini并禁用了所有新的OPcache,并将默认缓存时间设置为0。向文档添加了标头以强制不进行缓存。还是同样的问题。这里到底发生了什么? 网络标签显示的是HTTP 200请求,因此文件中的任何新HTML都可
启动无限循环后,我无法关闭JFrame。 我想停止无限循环使用停止按钮。 我用开始按钮开始一个无限循环。我想用“停止”按钮关闭那个回路。 > if(stop.getModel(). isP的()){中断;}不工作 actionListener用于识别按钮单击并在循环也不起作用时使用中断语句终止 点击停止按钮,无限循环必须终止。在使用start Button启动无限循环后,我无法使用JFrame中的
我有一个简单的UILabel,当你长按它时,它就会开始旋转。我使用以下代码成功地实现了这一点: 用户只需双击标签,就可以在任何时候停止这个动画。下面是代码: 问题是,下次你长按标签时,它没有反应。旋转动画不会再次启动。你必须再次点击它才能让它再次运行。 所以模式是: 1)长按-动画开始 2)双击-动画停止 3)长按-什么都没有发生 4)再次长按-动画再次开始 我该怎么解决这个问题?
我有一个程序,它每秒钟响一次,直到停止。问题是,在我按下“开始”并发出嘟嘟声后,我无法单击“停止”按钮,因为窗口冻结。欢迎任何帮助。