我想为我的PHP项目创建一个配置文件,但我不确定最好的方法是什么。
到目前为止我有3个想法。
1使用变量
$config['hostname'] = "localhost";
$config['dbuser'] = "dbuser";
$config['dbpassword'] = "dbpassword";
$config['dbname'] = "dbname";
$config['sitetitle'] = "sitetitle";
2使用Const
define('DB_NAME', 'test');
define('DB_USER', 'root');
define('DB_PASSWORD', '');
define('DB_HOST', 'localhost');
define('TITLE', 'sitetitle');
3用数据库
我将在课堂上使用配置,所以我不确定哪种方式最好或者有更好的方法。
一种简单但优雅的方法是创建一个只返回数组的config.php
文件(或任何你称之为的文件):
<?php
return array(
'host' => 'localhost',
'username' => 'root',
);
然后:
$configs = include('config.php');
这是我的方式。
<?php
define('DEBUG',0);
define('PRODUCTION',1);
#development_mode : DEBUG / PRODUCTION
$development_mode = PRODUCTION;
#Website root path for links
$app_path = 'http://192.168.0.234/dealer/';
#User interface files path
$ui_path = 'ui/';
#Image gallery path
$gallery_path = 'ui/gallery/';
$mysqlserver = "localhost";
$mysqluser = "root";
$mysqlpass = "";
$mysqldb = "dealer_plus";
?>
有任何疑问请评论
使用INI文件是一个灵活而强大的解决方案! PHP有a native function来正确处理它。例如,可以像这样创建一个INI文件:
app.ini
[database]
db_name = mydatabase
db_user = myuser
db_password = mypassword
[application]
app_email = [email protected]
app_url = myapp.com
所以你唯一需要做的就是打电话:
$ini = parse_ini_file('app.ini');
然后,您可以使用$ini
数组轻松访问定义。
echo $ini['db_name']; // mydatabase
echo $ini['db_user']; // myuser
echo $ini['db_password']; // mypassword
echo $ini['app_email']; // [email protected]
重要信息:出于安全原因,INI文件必须位于非公用文件夹中
我使用@hugo_leonardo的solution的轻微演变:
<?php
return (object) array(
'host' => 'localhost',
'username' => 'root',
'pass' => 'password',
'database' => 'db'
);
?>
这允许您在包含php:$configs->host
而不是$configs['host']
时使用对象语法。
此外,如果您的应用程序在客户端需要配置(例如Angular应用程序),您可以将此config.php
文件包含所有配置(集中在一个文件中,而不是一个用于JavaScript,一个用于PHP)。然后诀窍是有另一个PHP文件,它将echo
只有客户端信息(以避免显示您不希望显示信息数据库连接字符串)。叫它说get_app_info.php
:
<?php
$configs = include('config.php');
echo json_encode($configs->app_info);
?>
以上假设您的config.php
包含app_info
参数:
<?php
return (object) array(
'host' => 'localhost',
'username' => 'root',
'pass' => 'password',
'database' => 'db',
'app_info' => array(
'appName'=>"App Name",
'appURL'=> "http://yourURL/#/"
)
);
?>
因此,您的数据库信息保留在服务器端,但您的应用信息可以通过JavaScript访问,例如$http.get('get_app_info.php').then(...);
类型的调用。
我对这里接受的答案以及它所获得的赞成数量感到惊讶。除了Marcio Mazzucato的答案之外,没有讨论任何多种方法的相对优点/缺点。
我看到的选项是:
基于文件的机制
这些要求您的代码在特定位置查找以查找ini文件。这是一个难以解决的问题,并且总是在大型PHP应用程序中出现。但是,您可能需要解决问题才能找到在运行时合并/重用的PHP代码。
常见的方法是始终使用相对目录,或者从当前目录向上搜索以查找在应用程序的基本目录中专门命名的文件。
用于配置文件的常见文件格式是PHP代码,ini格式化文件,JSON,XML,YAML和序列化PHP
PHP代码
这为表示不同的数据结构提供了大量的灵活性,并且(假设它是通过include或require处理的),解析的代码将从操作码缓存中获得 - 从而提供性能优势。
include_path提供了一种抽象文件的潜在位置的方法,而不依赖于其他代码。
另一方面,将配置与代码分离的主要原因之一是分离职责。它提供了将其他代码注入运行时的路由。
如果配置是从工具创建的,则可以验证工具中的数据,但是没有标准函数来转义嵌入到PHP代码中的数据,如HTML,URL,MySQL语句,shell命令所存在的...... 。
序列化数据这对于少量配置(最多约200项)相对有效,并允许使用任何PHP数据结构。它只需要很少的代码来创建/解析数据文件(因此您可以花费精力确保文件仅使用适当的授权进行编写)。
将自动处理写入文件的内容的转义。
由于您可以序列化对象,因此只需通过读取配置文件(__wakeup魔术方法)就可以创建调用代码的机会。
结构化文件
根据Marcel或JSON或XML的建议将其存储为INI文件还提供了一个简单的api,用于将文件映射到PHP数据结构(除了XML,以逃避数据和创建文件),同时消除代码调用使用序列化PHP数据的漏洞。
它将具有与序列化数据类似的性能特征。
数据库存储
这是最好的考虑你有大量配置,但有选择性的当前任务所需 - 我惊讶地发现,在大约150个数据项,从本地MySQL实例检索数据比从反序列化数据文件。
OTOH它不是存储用于连接数据库的凭据的好地方!
执行环境
您可以在PHP运行的execution environment中设置值。
这消除了PHP代码在配置的特定位置查找的任何要求。 OTOH它不能很好地扩展到大量数据,并且很难在运行时普遍改变。
在客户端
我没有提到用于存储配置数据的一个地方是客户端。网络开销再次意味着这不能很好地扩展到大量配置。并且由于最终用户可以控制数据,因此它必须以可检测到任何篡改的格式(即,使用加密签名)存储,并且不应包含任何被其公开所损害的信息(即,可逆地加密)。
相反,这对于存储最终用户拥有的敏感信息有很多好处 - 如果您不将其存储在服务器上,则不能从那里窃取。
网络目录存储配置信息的另一个有趣的地方是DNS / LDAP。这将适用于少量小信息 - 但你不需要坚持第一范式 - 考虑,例如SPF。
基础结构支持缓存,复制和分发。因此,它适用于非常大的基础设施。
版本控制系统
配置与代码一样应该进行管理和版本控制 - 因此直接从VC系统获取配置是一个可行的解决方案。但通常这会带来显着的性能开销,因此缓存可能是可取的。
好吧 - 将数据库配置数据存储在数据库中会很困难 - 不管怎样?
但实际上,这是一个非常自以为是的问题,因为任何风格都是有效的,而且这都是偏好问题。就个人而言,我会选择配置变量而不是常量 - 通常是因为除非必要,否则我不喜欢全局空间中的东西。我的代码库中的所有函数都不应该能够轻松访问我的数据库密码(除了我的数据库连接逻辑) - 所以我在那里使用它然后可能会破坏它。
编辑:回答您的评论 - 解析机制中没有一个是最快的(ini,json等) - 但它们也不是您真正需要关注优化的应用程序的部分,因为速度差异会这些小文件可以忽略不计。
定义将使类中的常量可用,而不需要使用全局,而变量在类中需要全局,我会使用DEFINE。但同样,如果db params在程序执行期间发生变化,您可能希望坚持使用变量。
如果您认为由于任何原因您将使用超过1 db,请使用该变量,因为您将能够更改一个参数以切换到完全不同的db。即用于测试,自动备份等
您可以创建配置类的静态属性
class Config
{
static $dbHost = 'localhost';
static $dbUsername = 'user';
static $dbPassword = 'pass';
}
然后你可以简单地使用它:
Config::$dbHost
有时在我的项目中,我使用设计模式SINGLETON来访问配置数据。它使用起来非常舒适。
为什么?
例如,项目中有2个数据源。你可以选择启用它们的女巫。
在配置文件中的某个位置选择:
$dataSource = 'mysql' // or 'json'
当您将源整个应用程序shoud切换到新数据源时,工作正常,不需要更改代码。
例:
配置:
class Config
{
// ....
static $dataSource = 'mysql';
/ .....
}
单身人士课程:
class AppConfig
{
private static $instance;
private $dataSource;
private function __construct()
{
$this->init();
}
private function init()
{
switch (Config::$dataSource)
{
case 'mysql':
$this->dataSource = new StorageMysql();
break;
case 'json':
$this->dataSource = new StorageJson();
break;
default:
$this->dataSource = new StorageMysql();
}
}
public static function getInstance()
{
if (empty(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
public function getDataSource()
{
return $this->dataSource;
}
}
...以及代码中的某个地方(例如,在某些服务类中):
$container->getItemsLoader(AppConfig::getInstance()->getDataSource()) // getItemsLoader need Object of specific data source class by dependency injection
我们可以从系统中的任何位置获取AppConfig对象,并始终获得相同的副本(感谢静态)。类的init()方法在构造函数中调用,它只保证一次执行。 Init()body检查config $ dataSource的值,并创建特定数据源类的新对象。现在我们的脚本可以获取对象并对其进行操作,甚至不知道实际存在哪个特定实现。
我通常最终创建一个具有数据库连接的conn.php文件。然后我将该文件包含在需要数据库查询的所有文件中。