停止在PHP中使用'global'
我有一个停止在PHP中使用'global',php,Php,我有一个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.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
的情况下访问代码其他部分中的$config
谁能解释一下,为什么我不应该在我的例子中使用global
?有人说这是一个坏的语气,其他人说这是不安全的
编辑1:
我在何处以及如何使用它的示例:
function conversion($Exec, $Param = array(), $Log = '') {
global $config;
$cmd = $config['phppath'] . ' ' . $config['base_path'] . '/' . $Exec;
foreach ($Param as $s)
{
$cmd .= ' ' . $s;
}
}
编辑2:
正如所建议的,将所有这些放在类中是很酷的,但在本例中,我如何将其与从数据库中提取configkey
和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();
}
}
编辑3:
此外,我必须从配置中设置的函数中访问其他变量
,它们很少,例如:$db
,$language
等等
如果我把它们放在课堂上,它真的能解决什么问题吗?如果我使用global
它真正改变了什么
编辑4:
我读了where,它以非常好的方式解释了为什么不应该使用
global
。我同意一切,但我不会在我的案例中使用global
来重新分配变量,这将导致,就像他说的那样,对于您的案例,我将创建一个唯一的文件constants.php
(如果您的目的是这些“变量”在执行时永远不会更改):
将此constants.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();
在上面的任何一行中,您都可能会遇到错误,因为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);
我将把实现单独的类留给读者作为练习。当您尝试实现它们时,您会注意到它们非常容易实现,而且不需要单个全局
。每个函数和类都以函数参数的形式获得其所有必需的数据。显然,上述组件可以以任何其他组合插入在一起,或者依赖关系可以很容易地替换其他组件。例如,配置根本不需要来自数据库,或者记录器可以登录到一个文件而不是数据库,而不必知道这一切
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);
您可以将$co替换为
$config = $configManager->loadConfigurationFromDatabase($db);
class Config {
private static $config = array();
public static function set( $key, $value ) {
self::$config[$key] = $value;
}
public static function get( $key ) {
return isset( self::$config[$key] ) ? self::$config[$key] : null;
}
}
Config::set( 'my_config', 'the value' );
echo 'the config value is: ' . Config::get('my_config');
class Config {
private static $config = array();
public static function set( $key, $value ) {
self::$config[$key] = $value;
}
public static function get( $key ) {
return isset( self::$config[$key] ) ? self::$config[$key] : null;
}
public static function setAll( array $array ) {
self::$config = $array;
}
public static function isKeySet( $key ) {
return isset( self::$config[ $key ] );
}
}
Config::setAll( array(
'key' => 'value',
'key2' => array( 'value',
'can be an',
'array' ) ) );
Config::set( 'my_config', 'the value' );
if( Config::isKeySet( 'my_config' ) ) {
echo 'the config value is: ' . Config::get('my_config');
}
<?php
class config {
private static $config = array();
public static function set( $key, $value ) {
self::$config[$key] = $value;
}
public static function get( $key ) {
if( config::isKeySet( $key ) ) {
return isset( self::$config[$key] ) ? self::$config[$key] : null;
}
}
public static function setAll( array $array ) {
self::$config = $array;
}
public static function isKeySet( $key ) {
return isset( self::$config[ $key ] );
}
}
// set valuable values
config::setAll( array(
'key' => 'value',
'key2' => array( 'value', 'can be an', 'array' ),
'database' => array( "username" => "root", "password" => "root")
)
);
config::set( 'my_config', 'the value' );
?>
<?php
require_once 'config.php';
$database_credentials = config::get('database');
echo 'the config value for username is ' . $database_credentials['username'];
echo '<br> the config value for password is ' . $database_credentials['password'];
function additionalFunctionality($database_credentials)
{
echo '<br> the config value for password is ' . $database_credentials['password'];
}
?>
<?php
require_once 'config.php'; // put this first
require_once 'config.usage.php'; // include some functionality from another file
$database_credentials = Config::get('database');
echo 'the config value for username is ' . $database_credentials['username'];
additionalFunctionality($database_credentials); // great
?>