Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/254.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
停止在PHP中使用'global'_Php - Fatal编程技术网

停止在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: 正如所建议的,将所有这些放在类中是很酷的,但在本例中,我如何将其与从数据库中提取config
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();
    }
}
编辑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
?>