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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3724584/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 10:53:27  来源:igfitidea点击:

What is the best way to save config variables in a PHP web app?

phpconfiguration

提问by Edward Tanguay

I often switch between .NET and PHP development. With ASP.NET sitesI save configuration information (e.g. connection strings, directories, application setting) in the web.configfile which is appropriately protected and easy to access the values, etc.

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

In PHP, I solve this with a class that has static methodsfor each variable:

PHP 中,我使用一个为每个变量提供静态方法类来解决这个问题:

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

The file is includedby the app variables are accessed with a one-line:

该文件包含在 app 变量中,通过一行访问:

$dp = webconfig::defaultPageIdCode();

And since PHP isn't compiled, it is easy to telnetin and change a value for a website anyway, so this solution works fairly welland gives me these two advantages:

由于 PHP 未编译,因此无论如何都可以轻松通过telnet 登录并更改网站的值,因此该解决方案运行良好,并为我提供了以下两个优点

  • I can add logicto a config variable without breaking its interface with the application
  • these config variables appear as intellisensein my e.g. Eclipse, NetBeans, etc.
  • 我可以不破坏其与应用程序的接口的情况下向配置变量添加逻辑
  • 这些配置变量在我的例如 Eclipse、NetBeans 等中显示为智能感知

But I can imagine there are other ways people solve saving web config settings in PHP which may have other advantages.

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

Especially those who have experience with a number of PHP frameworks, what are other ways of saving config variables and their advantages and disadvantages?

尤其是对一些PHP框架有使用经验的人,还有哪些保存配置变量的方法及其优缺点?

回答by raveren

I've decided to list all known methods along with their advantages and disadvantages.

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

I've marked this answer as a community wiki so collaboration is easier.

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



Global Constants

全局常量

Assigning:

分配:

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

Accessing:

访问:

  • $object = new MyObject(CONFIG_DIRECTIVE);
  • $object = new MyObject(CONFIG_DIRECTIVE);

Advantages:

好处:

  • Has global scope.
  • Autocompleted by most IDEs.
  • Has an agreed upon naming convention (UPPERCASE_UNDERSCORE_SEPARATED).
  • 具有全球范围。
  • 大多数 IDE 自动完成。
  • 有一个商定的命名约定(UPPERCASE_UNDERSCORE_SEPARATED)

Disadvantages:

缺点:

  • Directives cannot contain arrays (prior to v7.0.0).
  • 指令不能包含数组(v7.0.0 之前)。

Special Notes:

特别说明:

  • Cannot be reassigned.
  • 不能重新分配。


Alternate Syntax Files

替代语法文件

For example: XML, INI, YAML, etc.

例如:XML、INI、YAML 等。

Assigning:

分配:

  • Simply edit the file in it's specific language. (For example, for INI files: config_directive = value.)
  • 只需用它的特定语言编辑文件。(例如,对于 INI 文件:config_directive = value.)

Accessing:

访问:

  • The config file needs to be parsed. (For example, for INI's: parse_ini_file().)
  • 需要解析配置文件。(例如,对于 INI 的:parse_ini_file().)

Advantages:

好处:

  • Most likely has a syntax more suited for a config file.
  • 很可能有更适合配置文件的语法。

Disadvantages:

缺点:

  • Possible overhead of accessing and parsing the file.
  • 访问和解析文件的可能开销。


Array

大批

Assigning:

分配:

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

Accessing:

访问:

  • The cleanest method of accessing configuration values using this method is to pass the required values to the object that needs them on creation, or pass them to your container object and let it handle passing them out internally.
    • $object = new MyObject($config['directive']);
    • $container = new MyContainer($config);
  • 使用此方法访问配置值的最干净的方法是将所需的值传递给创建时需要它们的对象,或者将它们传递给您的容器对象并让它处理在内部传递它们。
    • $object = new MyObject($config['directive']);
    • $container = new MyContainer($config);

Advantages:

好处:

  • Directives can be arrays.
  • 指令可以是数组。

Disadvantages:

缺点:

  • No autocompletion.
  • 没有自动完成。

Special Notes:

特别说明:

  • Variable collisions can occur. If this is a concern, name your array appropriately to avoid them.
  • 可能会发生变量冲突。如果这是一个问题,请适当命名您的数组以避免它们。


Class

班级

Assigning:

分配:

  • There are many different class based implementations.
    • Static class.
      • myCfgObj::setDirective('DIRECTIVE', 'value');
    • Instanced class.
      • myCfgObj->setDirective('DIRECTIVE', 'value');
  • 有许多不同的基于类的实现。
    • 静态类。
      • myCfgObj::setDirective('DIRECTIVE', 'value');
    • 实例化类。
      • myCfgObj->setDirective('DIRECTIVE', 'value');

Accessing:

访问:

  • Again there are various class based implementations.
    • Static class.
      • $object = new MyObject(myCfgObj::getDirective('DIRECTIVE'));
    • Instanced class.
      • $object = new MyObject(myCfgObj->getDirective('DIRECTIVE'));
  • 同样有各种基于类的实现。
    • 静态类。
      • $object = new MyObject(myCfgObj::getDirective('DIRECTIVE'));
    • 实例化类。
      • $object = new MyObject(myCfgObj->getDirective('DIRECTIVE'));

Advantages:

好处:

  • Can be autoloaded.
  • 可以自动加载。

Disadvantages:

缺点:

  • Tends to be a bit verbose.
  • Can be hard to maintain if a container class is not being used.
  • 往往有点冗长。
  • 如果未使用容器类,则可能难以维护。

回答by RobertPitt

I tend to use a Settings static class in PHP, this is because

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

  • It has a global scope.
  • You can enable/disable changes to protected configs.
  • You can add any settings during anywhere within runtime.
  • You can make the class automated to fetch public configs from a file/database.
  • 它具有全球范围。
  • 您可以启用/禁用对受保护配置的更改。
  • 您可以在运行时的任何位置添加任何设置。
  • 您可以使该类自动化以从文件/数据库中获取公共配置。

Example:

例子:

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

Then within your runtime, if you loaded this file first, followed by your database config file, your database config file would look like so:

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

<?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/');

As you can see the we have a method __getthat should only be allowed to grab public variables, An example of why we have this is as follows:

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

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

Regardless the fact that we have used this object as a static object, the values should still stand so within the template you can now do, lets say.

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

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

And this will only allow you to have access to the public data during the initialized period.

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

This can get a lot more complex but more system friendly, some examples:

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

  • A loadConfigmethod to automatically parse a config file, xml, php, yaml.
  • If you register an shutdown_functionyou can auto update the database with new settings.
  • You can auto-populate the class with config from that database.
  • You can implement iterators to make it compatible with looping.
  • Lots more.
  • 一种loadConfig自动解析配置文件、xml、php、yaml 的方法。
  • 如果您注册一个,shutdown_function您可以使用新设置自动更新数据库。
  • 您可以使用该数据库中的配置自动填充该类。
  • 您可以实现迭代器以使其与循环兼容。
  • 还有很多。

This too me is by far the best methods to complete this job.

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

回答by shamittomar

The way I do it is directly store them in an arrayand save the file as config.php

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

<?php

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

?>

Thi is the way most PHP frameworks like Wordpress, etc do it.

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

回答by Oyeme

In PHP I always use a ".htaccess" to protect my config file (Double protection)

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

回答by fabrik

Note: "Best way" never exists. Every application and framework doing it their own style. While your example is doing the trick i think it's a little bit resource-heavy for a simple config file.

注意:“最佳方式”永远不存在。每个应用程序和框架都有自己的风格。虽然您的示例正在发挥作用,但我认为对于一个简单的配置文件来说,它有点占用大量资源。

  • You can do it with single variables like Amber pointed out
  • You can do it with arrays this is the most common approach and you can always easily edit your config file.
  • You can do it with .ini files that PHP easily parsing
  • 您可以使用 Amber指出的单个变量来实现
  • 您可以使用数组来完成,这是最常见的方法,您可以随时轻松编辑配置文件。
  • 您可以使用 PHP轻松解析的.ini 文件来完成

Edit:

编辑:

Edward please take a look at parse_ini_file's examples. You can load the .ini file with a simple command then you can use the variables in a class like in your example.

爱德华请看一下 parse_ini_file 的例子。您可以使用一个简单的命令加载 .ini 文件,然后您可以使用类中的变量,例如您的示例。

回答by Fidi

There are pretty much possibilities I think, but the most common methods are storing as plain text in files like .csv, .ini, .xml. With little tricks you can protect these files, so that no one can load the files directly.

我认为有很多可能性,但最常见的方法是将纯文本存储在 .csv、.ini、.xml 等文件中。您可以使用一些小技巧来保护这些文件,这样就没有人可以直接加载这些文件。

an INI-File example:

一个 INI 文件示例:

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

The ;is considered a comment in ini files. So when you read in the file with an ini-parser, this line will be ignored. If someone accesses the file directly via url the die()-function will be executed. This works only, if the INI-file wears a file-extension like .php so that the server knows that this should be executed and not diplayed as plain text.

;被认为是INI文件的注释。所以当你用 ini-parser 读入文件时,这一行将被忽略。如果有人直接通过 url 访问文件,则die()-function 将被执行。这只适用,如果 INI 文件带有像 .php 这样的文件扩展名,以便服务器知道这应该被执行而不是作为纯文本显示。

Possible disadvantage of most file-base-config-storages are problems with some utf8-characters.

大多数文件基础配置存储的可能缺点是一些 utf8 字符的问题。

Zend_Configis a component of the Zend-Framework, which provides possibilities for several storage-adapters with an easy to use api.

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

回答by DrColossos

Since PHP is able to use OO, I like to go with a "Config class":

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

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

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

    const DB_USER = 'postgres';

    const DB_PASSWORD = 'postgres';

    const DB_NAME = 'postgres';
}

It is easy accessable with Config::DB_DRIVER. No need to include the file since the application autoloader will do that for you. Of course, protecting the file still needs to be done.

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

回答by symcbean

Telnet? OMG I've fallen into a timewarp and arrived in 1992!

远程登录?天哪,我陷入了时间扭曲并于 1992 年抵达!

But seriously, IIRC there are tools which allow asp.net (and other languages) to parse session data - which is just a serialized php array. I'd have a go at implementing the global settings as a sort of shadow session within PHP. Even if you don't store your config settings as a serialized PHP array, you could map them into the session at runtime using your own session handler.

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

In terms of where you store the data - that's a more tricky one when you're presumably running on a Microsoft platform. Obviously you don't want the expense of disk access for every request. Although NT does some disk caching it's not (IME) quite as effective as other OS. Memcachedappears to be one solution to this. It does appear to be usablefrom asp.net.

就您存储数据的位置而言 - 当您大概在 Microsoft 平台上运行时,这是一个更棘手的问题。显然,您不希望为每个请求支付磁盘访问费用。尽管 NT 进行了一些磁盘缓存,但它 (IME) 并不像其他操作系统那样有效。Memcached似乎是解决此问题的一种方法。它似乎可以从 asp.net 使用。

HTH

HTH

回答by ts.

There are few possibilities:

有几种可能:

  1. You can use config file (ini, json, xml or yaml). For ini you have parse_ini_file, for JSON there is json_decode(+file_get_contents), for YAML you have to use external library (search for sfYaml)

  2. You can have a config file with variables or constants (better for immutable config and accessible in all scopes), which you includes in your script:

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

    $sRootDir = '\home\www';

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

  2. 您可以拥有一个包含变量或常量的配置文件(更适合不可变配置并可在所有范围内访问),您可以将其包含在脚本中:

    定义('ROOT_DIR', '\home\www');

    $sRootDir = '\home\www';

If you are OO-oriented, you can wrap it in class, as properties - you do not have getter method for every property, you can just have:

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

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

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

($c = new Config(); 打印 $c->var1)

or

或者

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

(print c::$var1)

(打印 c::$var1)

The best is to have registry-type class, implementing singleton pattern and capable to read config from given file.

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

回答by raveren

The usual route is to use define:

通常的路线是使用define

define('MYSQL_USER', 'ROOT');

and access it all over the application via MYSQL_USER:

并通过MYSQL_USER以下方式在整个应用程序中访问它:

$user = MYSQL_USER;

However arrays are not supported in this way.

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