在PHP Web应用程序中保存configurationvariables的最佳方法是什么?

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

PHP中 ,我用一个对每个variables都有静态方法类来解决这个问题:

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

该文件是由应用程序包含的variables访问一行:

 $dp = webconfig::defaultPageIdCode(); 

而且由于PHP没有编译,所以很容易远程login和更改一个网站的值,所以这个解决scheme工作得很好 ,给了我这两个好处

  • 我可以添加逻辑到一个configurationvariables,而不会中断它与应用程序的接口
  • 这些configurationvariables在我的例如Eclipse,NetBeans等中显示为intellisense

但我可以想象有其他的方式,人们可以解决在PHP中保存网页configuration设置,可能有其他的优势。

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

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

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


全局常量

分配:

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

访问:

  • $object = new MyObject(CONFIG_DIRECTIVE);

优点:

  • 具有全球范围。
  • 由大多数IDE自动完成。
  • 有一个约定的命名约定(UPPERCASE_UNDERSCORE_SEPARATED)

缺点:

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

特别提示:

  • 不能重新分配。

备用语法文件

例如:XML,INI,YAML等

分配:

  • 只需编辑它的特定语言的文件。 (例如,对于INI文件: config_directive = value 。)

访问:

  • configuration文件需要parsing。 (例如,对于INI: parse_ini_file() 。)

优点:

  • 最有可能有一个更适合于configuration文件的语法。

缺点:

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

排列

分配:

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

访问:

  • 使用此方法访问configuration值的最简单的方法是将所需的值传递给创build时需要它们的对象,或者将它们传递给容器对象,并让它在内部传递它们。
    • $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'));

优点:

  • 可以自动加载。

缺点:

  • 往往会有点冗长。
  • 如果没有使用容器类,可能难以维护。

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

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

例:

 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]); } } 

然后在你的运行时,如果你先加载这个文件,然后是你的数据库configuration文件,你的数据库configuration文件看起来是这样的:

 <?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 ,应该只允许获取公共variables,为什么我们有这样的一个例子如下:

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

不pipe我们用这个对象作为一个静态对象的事实,值仍然应该在你现在可以做的模板中。

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

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

这可以得到更复杂但更系统友好的一些例子:

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

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

我这样做的方式是直接将它们存储在一个array并保存为config.php文件

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

这是大多数PHP框架,如Wordpress等的做法。

注意:“最佳方式”从来不存在。 每个应用程序和框架都在做自己的风格。 虽然你的例子是在做的伎俩,我认为这是一个简单的configuration文件有点资源沉重。

  • 你可以用Amber 指出的单个variables来做到这一点
  • 你可以用数组来完成,这是最常用的方法,你总是可以轻松地编辑你的configuration文件。
  • 您可以使用PHP 轻松parsing的 .ini文件来完成

编辑:

Edward请看看parse_ini_file的例子。 你可以用一个简单的命令加载.ini文件,然后你可以在你的例子中使用类中的variables。

我想有很多可能性,但最常见的方法是将文件存储为.csv,.ini,.xml等文件。 用一些小技巧你可以保护这些文件,以便没有人可以直接加载文件。

一个INI文件的例子:

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

The ; 被认为是在ini文件中的评论。 所以当你用ini-parser读入文件时,这行会被忽略。 如果有人通过url直接访问文件, die()函数将被执行。 这只有在INI文件使用.php这样的文件扩展名的情况下才起作用,以便服务器知道这个文件应该被执行,而不是以纯文本的forms显示。

大多数文件基本configuration存储可能的缺点是一些UTF8字符的问题。

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

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

由于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很容易访问。 由于应用程序自动加载器将为您执行此操作,因此无需包含该文件。 当然,保护文件仍然需要完成。

远程login? OMG我已经陷入了时间的颠簸,到了1992年!

但严重的是,IIRC有允许asp.net(和其他语言)parsing会话数据的工具 – 这只是一个序列化的PHP数组。 我想在PHP中实现全局设置作为一种阴影会话。 即使不将configuration设置作为序列化的PHP数组存储,也可以使用自己的会话处理程序将它们映射到会话中。

就存储数据的位置而言 – 当您大概在Microsoft平台上运行时,这是一个比较棘手的问题。 很明显,您不希望为每个请求花费磁盘访问。 虽然NT做了一些磁盘caching,但它不像其他操作系统那样有效(IME)。 Memcached似乎是一个解决scheme。 它确实似乎可以从asp.net使用。

HTH

通常的路线是使用define

 define('MYSQL_USER', 'ROOT'); 

并通过MYSQL_USER在应用程序中访问它:

 $user = MYSQL_USER; 

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

有几种可能性:

  1. 你可以使用configuration文件(ini,json,xml或yaml)。 对于ini你有parse_ini_file ,对于JSON有json_decode (+ file_get_contents),对于YAML你必须使用外部库(searchsfYaml)

  2. 你可以在你的脚本中包含一个包含variables或常量的configuration文件(更适合不可变的configuration,并且可以在所有的作用域中访问):

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

    $ sRootDir ='\ home \ www';

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

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

($ c = new Config(); print $ c-> var1)

要么

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

(打印c :: $ var1)

最好是具有registry类,实现单例模式,并能够从给定的文件读取configuration。

为了可testing,我使用一个Config类来保存实际的configuration数据和一个AppConfig静态类,该类保存对引导程序中从应用程序范围的configuration文件(引导时注入的依赖项)加载的Config对象的引用。 在testing环境中,我只更改Config对象。 请参阅https://github.com/xprt64/Config