我有一个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
来访问它-这就是我想要摆脱的!
如何在不使用global
的情况下访问代码的其他部分?
谁能解释一下,为什么我不应该在我的示例中使用global
?有人说这是一个坏的语气,其他人说这是不安全的?
我在哪里以及如何使用它的示例:
function conversion($Exec, $Param = array(), $Log = '') {
global $config;
$cmd = $config['phppath'] . ' ' . $config['base_path'] . '/' . $Exec;
foreach ($Param as $s)
{
$cmd .= ' ' . $s;
}
}
按照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();
}
}
此外,我必须从配置中设置的函数中访问其他vars
,其中很少,例如:$db
,$语言
等。
如果我把它们放在课堂上,它真的能解决什么问题吗?如果我使用global
它真正改变了什么?
我在函数中阅读了PHP全局函数,Gordon以非常好的方式解释了为什么不应该使用global
。我同意一切,但在我的情况下,我不使用global
来重新分配变量,这将导致,就像他说的那样,
在同一个PHP全局函数中,deceze说:“反对全局的一个主要原因是它意味着函数依赖于另一个作用域。这将很快变得混乱。”
但是我在这里谈论的是基本的“INIT”。我基本上设置了
定义
,但使用了vars
-这在技术上是错误的。但是你的函数不依赖于任何东西——但是你可以记住的一个var$db
的名字?它确实需要全局使用$db
,这里的依赖在哪里以及如何使用它?
另外,我刚才有一个想法,我们在这里面临着两种不同思想的冲突,例如:我的(还没有很好地理解面向对象编程)和那些在OOP中可以被称为大师(从我目前的观点来看)的人——他们对我来说显而易见的东西产生了新的问题。我想这就是为什么人们一遍又一遍地问这个问题。就我个人而言,这已经变得更加清晰,但仍然有一些事情需要澄清。
对于您的情况,我将只创建一个文件常量。php
和定义(如果您的目的是在执行时永远不要更改这些“变量”):
define('SITE_NAME','site name');
define('BASE_PATH','/home/docs/public_html/');
...
包括这个常量。php
在您需要的所有文件中:
include_once('constants.php');
我用一门课解决了这个问题:
class Config
{
public static $SiteName = 'My Cool Site';
}
function SomeFunction
{
echo 'Welcome to ' , Config::$SiteName;
}
fcortes关于使用常量的建议也是一个很好的建议。我只想建议给所有常量一个前缀,比如CFG\u SITE\u NAME
,以避免与其他常量发生意外的名称冲突。
反对全局
变量的一点是它们非常紧密地耦合代码。您的整个代码库依赖于a)变量名称$config
和b)该变量的存在。如果您想重命名变量(无论出于什么原因),您必须在代码库中的任何地方重命名。您也不能再使用任何独立于变量的代码。
带有全局变量的示例:
require 'SomeClass.php';
$class = new SomeClass;
$class->doSomething();
在上述行中的任何地方,您都可能会得到一个错误,因为类或
lass.php
中的某些代码隐含地依赖于一个全局变量$config
。尽管只是看了看班级,但没有任何迹象表明这一点。为了解决这个问题,你必须这样做:
$config = array(...);
require 'SomeClass.php';
$class = new SomeClass;
$class->doSomething();
如果您没有在
$config
中设置正确的键,此代码仍可能在某个地方失败。由于配置数组的哪些部分需要或不需要以及何时需要并不明显,因此很难重新创建正确的环境以使其正确运行。如果你碰巧已经有了一个变量$config
,在你想使用某些类
的任何地方,它也会产生冲突。
因此,与其创建隐式的、不可见的依赖关系,不如注入所有依赖关系:
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);
我将把个别类的实现作为读者的练习。当您尝试实现它们时,您会注意到它们非常容易和清晰地实现,并且不需要单个
global
。每个函数和类都以函数参数的形式传递其所有必要的数据。同样显而易见的是,上述组件可以在任何其他组合中插在一起,或者依赖关系可以很容易地替代其他组件。例如,配置根本不需要来自数据库,或者记录器可以登录到一个文件而不是数据库,而不需要知道这些。
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
方法本身也不依赖于任何一个特定的数据库连接,只要它可以调用query
,并获取结果。传递给它的$db
对象可能是完全伪造的,并从XML文件或其他任何地方读取其数据,只要其接口的行为仍然相同。
问题内容: 我有一个包含在每个页面中。在配置中,我创建一个看起来像这样的数组: 然后,我有了,几乎每个页面也都包含,我必须使用它来访问它- 这 就是我要摆脱的东西! 如何在不使用代码的情况下访问代码的其他部分? 谁能解释, 为什么 我不应该在示例中使用?有人说这是一个不好的语气,有人说这是不安全的? 编辑1: 我在哪里以及如何使用它的示例: 编辑2: 按照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)再次长按-动画再次开始 我该怎么解决这个问题?
我有一个程序,它每秒钟响一次,直到停止。问题是,在我按下“开始”并发出嘟嘟声后,我无法单击“停止”按钮,因为窗口冻结。欢迎任何帮助。