在PHP Web应用程序中保存配置变量的最佳方法是什么?

时间:2010-09-16 07:34:03

标签: php configuration

我经常在.NET和PHP开发之间切换。使用 ASP.NET站点,我在 web.config 文件中保存配置信息(例如连接字符串,目录,应用程序设置),该文件受到适当保护并且易于访问值,等

PHP 中,我使用每个变量的类具有静态方法解决此问题:

class webconfig {
    public static function defaultPageIdCode() {
        return 'welcome';
    }
}

应用变量的文件包含是通过一行访问的:

$dp = webconfig::defaultPageIdCode();

由于PHP未编译,因此很容易 telnet 并更改网站的值,因此此解决方案运行良好并给我这些两个优点

  • 我可以将逻辑添加到配置变量,而不会破坏与应用程序的接口
  • 这些配置变量在我的例如中显示为 intellisense Eclipse,NetBeans等

但我可以想象,人们可以通过其他方式解决在PHP中保存Web配置设置的问题,这可能还有其他优势。

特别是那些有许多PHP框架经验的人,还有其他保存配置变量的方法及其优缺点?

11 个答案:

答案 0 :(得分:36)

我决定列出所有已知的方法及其优点和缺点。

我已将此答案标记为社区维基,因此协作更容易。


全局常量

分配:

  • define('CONFIG_DIRECTIVE', 'value');

访问:

  • $object = new MyObject(CONFIG_DIRECTIVE);

优点:

  • 具有全球范围。
  • 大多数IDE自动完成。
  • 已达成一致同意的命名约定(UPPERCASE_UNDERSCORE_SEPARATED)

缺点:

  • 指令不能包含数组(在v7.0.0之前)。

特别说明:

  • 无法重新分配。

备用语法文件

例如:XML,INI,YAML等

分配:

  • 只需使用其特定语言编辑文件即可。 (例如,对于INI文件:config_directive = value。)

访问:

  • 需要解析配置文件。 (例如,对于INI的:parse_ini_file()。)

优点:

  • 最有可能的语法更适合配置文件。

缺点:

  • 访问和解析文件的可能开销。

阵列

分配:

  • $config['directive'] = 'value';

访问:

  • 使用此方法访问配置值的最干净方法是将所需的值传递给创建时需要它们的对象,或者将它们传递给容器对象并让它在内部处理它们。
    • $object = new MyObject($config['directive']);
    • $container = new MyContainer($config);

优点:

  • 指令可以是数组。

缺点:

  • 没有自动完成。

特别说明:

  • 可能发生可变冲突。如果这是一个问题,请相应地命名您的数组以避免它们。

分配:

  • 有许多不同的基于类的实现。
    • 静态类。
      • myCfgObj::setDirective('DIRECTIVE', 'value');
    • 实例课程。
      • myCfgObj->setDirective('DIRECTIVE', 'value');

访问:

  • 同样有各种基于类的实现。
    • 静态类。
      • $object = new MyObject(myCfgObj::getDirective('DIRECTIVE'));
    • 实例课程。
      • $object = new MyObject(myCfgObj->getDirective('DIRECTIVE'));

优点:

  • 可以自动加载。

缺点:

  • 倾向于有点冗长。
  • 如果未使用容器类,则很难维护。

答案 1 :(得分:23)

我倾向于在PHP中使用Settings静态类,这是因为

  • 它具有全球范围。
  • 您可以启用/禁用对受保护配置的更改。
  • 您可以在运行时的任何位置添加任何设置。
  • 您可以使类自动从文件/数据库中获取公共配置。

示例:

abstract class Settings
{
    static private $protected = array(); // For DB / passwords etc
    static private $public = array(); // For all public strings such as meta stuff for site

    public static function getProtected($key)
    {
        return isset(self::$protected[$key]) ? self::$protected[$key] : false;
    }

    public static function getPublic($key)
    {
        return isset(self::$public[$key]) ? self::$public[$key] : false;
    }

    public static function setProtected($key,$value)
    {
        self::$protected[$key] = $value;
    }

    public static function setPublic($key,$value)
    {
        self::$public[$key] = $value;
    }

    public function __get($key)
    {//$this->key // returns public->key
        return isset(self::$public[$key]) ? self::$public[$key] : false;
    }

    public function __isset($key)
    {
        return isset(self::$public[$key]);
    }
}

然后在运行时,如果先加载此文件,然后加载数据库配置文件,那么数据库配置文件将如下所示:

<?php
Settings::setProtected('db_hostname', 'localhost');
Settings::setProtected('db_username', 'root');
Settings::setProtected('db_password', '');
Settings::setProtected('db_database', 'root');
Settings::setProtected('db_charset', 'UTF-8');
//...
echo Settings::getProtected('db_hostname'); // localhost
//...
Settings::setPublic('config_site_title', 'MySiteTitle');
Settings::setPublic('config_site_charset', 'UTF-8');
Settings::setPublic('config_site_root', 'http://localhost/dev/');

正如您所看到的,我们有一个方法__get,只允许获取公共变量,我们为什么这样做的例子如下:

$template = new Template();
$template->assign('settings', new Settings());

无论我们将此对象用作静态对象,我们现在可以在模板中使用这些值。比如说。

<html>
    <head>
        <?php echo isset($settings->config_site_title) ? $settings->config_site_title : 'Fallback Title'; ?>
    </head>
</html>

这只允许您在初始化期间访问公共数据。

这可能会变得更复杂但更加系统友好,例如:

  • 一个loadConfig方法,用于自动解析配置文件,xml,php,yaml。
  • 如果您注册了shutdown_function,则可以使用新设置自动更新数据库。
  • 您可以使用该数据库中的配置自动填充该类。
  • 您可以实现迭代器以使其与循环兼容。
  • 还有很多。

这也是我迄今为止完成这项工作的最佳方法。

答案 2 :(得分:5)

我这样做是直接将它们存储在array中并将文件另存为config.php

<?php

$config['dbname'] = "mydatabase";
$config['WebsiteName'] = "Fundoo Site";
$config['credits'] = true;
$config['version'] = "4.0.4";

?>

这是大多数PHP框架如Wordpress等的方式。

答案 3 :(得分:2)

注意:“最佳方式”永远不存在。每个应用程序和框架都以自己的风格完成。虽然你的例子正在做诀窍,但我认为对于一个简单的配置文件来说它有点资源。

  • 您可以使用单个变量(例如Amber pointed out
  • )来执行此操作
  • 您可以使用数组执行此操作,这是最常用的方法,您可以随时轻松编辑配置文件。
  • 您可以使用PHP easily parsing
  • 的.ini文件来执行此操作

修改

Edward请看一下parse_ini_file的例子。您可以使用简单的命令加载.ini文件,然后您可以在类中使用变量,就像您的示例中一样。

答案 4 :(得分:2)

我认为有很多可能性,但最常见的方法是将文本存储为.csv,.ini,.xml等文件。通过一些小技巧,您可以保护这些文件,这样任何人都无法直接加载文件。

INI-File示例:

;<?php die(); ?>
[config1]
var1 = 'value1';
var2 = 'value2';
...
[config2]
...

;被视为ini文件中的评论。因此,当您使用ini-parser读入文件时,此行将被忽略。如果有人通过url直接访问该文件,则会执行die() - 函数。这仅适用于INI文件使用.php等文件扩展名,以便服务器知道应该执行此操作而不是以纯文本形式显示。

大多数file-base-config-storage的可能缺点是某些utf8字符存在问题。

Zend_Config是Zend-Framework的一个组件,它为多个存储适配器提供了易于使用的API的可能性。

答案 5 :(得分:1)

在PHP中,我总是使用“.htaccess”来保护我的配置文件(双重保护)

答案 6 :(得分:1)

由于PHP能够使用OO,我喜欢使用“Config类”:

class Config
{
    /**
     * ---------------------------------
     * Database - Access
     * --------------------------------- 
     */

    /**
     * @var String
     */
    const DB_DRIVER = 'pgsql';

    const DB_USER = 'postgres';

    const DB_PASSWORD = 'postgres';

    const DB_NAME = 'postgres';
}

使用Config :: DB_DRIVER可以轻松访问。无需包含该文件,因为应用程序自动加载器将为您执行此操作。当然,仍然需要保护文件。

答案 7 :(得分:0)

通常的路线是使用define

define('MYSQL_USER', 'ROOT');

并通过MYSQL_USER

访问整个应用程序
$user = MYSQL_USER;

但是这种方式不支持数组。

答案 8 :(得分:0)

几乎没有可能:

  1. 您可以使用配置文件(ini,json,xml或yaml)。对于ini,您有parse_ini_file,对于JSON,有json_decode(+ file_get_contents),对于YAML,您必须使用外部库(搜索sfYaml)

  2. 您可以拥有一个包含变量或常量的配置文件(对于不可变配置更好,并且可在所有范围内访问),您可以在脚本中包含这些配置文件:

    define('ROOT_DIR','\ home \ www');

    $ sRootDir ='\ home \ www';

  3. 如果你是面向OO的,你可以把它包装在类中,作为属性 - 你没有每个属性的getter方法,你可以只有:

    class Config
    {
        public $var1 = 'xxx';
        public $var2 = 'yyy';
    }
    

    ($ c = new Config(); print $ c-&gt; var1)

    static class Config
    {
        public static $var1 = 'xxx';
        public static $var2 = 'yyy';
    }
    

    (print c :: $ var1)

    最好的是拥有注册表类型类,实现单例模式并能够从给定文件中读取配置。

答案 9 :(得分:0)

的Telnet?我已经陷入了时间扭曲,并于1992年到来!

但严重的是,IIRC有一些工具允许asp.net(和其他语言)解析会话数据 - 这只是一个序列化的php数组。我将实现全局设置作为PHP中的一种影子会话。即使您没有将配置设置存储为序列化PHP数组,也可以使用自己的会话处理程序在运行时将它们映射到会话中。

就存储数据的位置而言 - 当您可能在Microsoft平台上运行时,这是一个更棘手的问题。显然,您不希望每个请求都支付磁盘访问费用。虽然NT做了一些磁盘缓存但它(IME)并不像其他操作系统那样有效。 Memcached似乎是一个解决方案。它来自asp.net。{/ p>。appear to be usable

HTH

答案 10 :(得分:0)

为了可测试,我使用一个包含实际配置数据的Config类和一个AppConfig静态类,该类包含对从应用程序引导时加载的Config对象的引用宽配置文件(在引导程序注入的依赖项)。在测试环境中,我只更改Config对象。见https://github.com/xprt64/Config