构建可配置PHP应用程序的方式有哪些-创新互联

本篇内容主要讲解“构建可配置PHP应用程序的方式有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“构建可配置PHP应用程序的方式有哪些”吧!

成都创新互联公司服务项目包括延安网站建设、延安网站制作、延安网页制作以及延安网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,延安网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到延安省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!

使用INI文件进行配置


PHP内建了对配置文件的支持。这是通过php.ini文件这样的初始化文件(INI)机制实现的,在php.ini文件中定义了数据库连接超时或会话如何存储等常量。如果愿意的话,可以在这个php.ini文件中为应用程序定制配置。为了说明,我将下列代码行添加到php.ini文件中。

myapptempdir=foo

然后,我编写了一个小PHP脚本来读取这个配置项,如清单1所示。

清单1.ini1.php

functionget_template_directory()

{

$v=get_cfg_var("myapptempdir");

return($v==null)?"tempdir":$v;

}

echo(get_template_directory()."\n");

?>

当在命令行中运行这段代码时,得到如下结果:

%phpini1.php

foo

%

太棒了。但为什么不能用标准的INI函数来获取myapptempdir配置项的值呢?我研究了一下,发现在大多数情况下,定制配置项不能使用这些方法来获取。然而,使用get_cfg_var函数却是可以访问的。

为使这个方法更加简单,将对变量的访问封装在第二个函数中,该函数使用配置键名及一个缺省值作为参数,如下所示。

清单2.ini2.php

functionget_ini_value($n,$dv)

{

$c=get_cfg_var($n);

return($c==null)?$dv:$c;

}

functionget_template_directory()

{

returnget_ini_value("myapptempdir","tempdir");

}

这是对如何访问INI文件的一个很好的概括,所以,如果要使用一个不同的机制或将这个INI文件存储到其他位置,就不需要为更改大量的函数而大费周折。

我不推荐使用INI文件作为应用程序的配置,这有两个理由。首先,虽然这样做较容易读取INI文件,但却几乎不可能安全地写INI文件。所以这样做只适合于只读配置项。第二,php.ini文件在服务器的所有应用程序上共享,所以我认为特定于应用程序的配置项不应该写在该文件中。

需要对INI文件了解什么呢?最重要的是如何重置include路径来添加配置项,如下所示。

清单3.ini3.php

echo(ini_get("include_path")."\n");

ini_set("include_path",

ini_get("include_path").":./mylib");

echo(ini_get("include_path")."\n");

?>

在本例中,我将我的本地mylib目录添加到了include路径中,所以能够从该目录中requirePHP文件,而不需要将该路径添加到require语句中。

PHP中的配置

通常对于在INI文件中存储配置条目的一个替代办法是使用一个简单的PHP脚本来保持数据。如下是一个样例。

清单4.config.php

#Specifythelocationofthetemporarydirectory

#

$TEMPLATE_DIRECTORY="tempdir";

?>

使用该常量的代码如下所示。

清单5.php.php

require_once'config.php';

functionget_template_directory()

{

global$TEMPLATE_DIRECTORY;

return$TEMPLATE_DIRECTORY;

}

echo(get_template_directory()."\n");

?>

该代码首先包含配置文件(config.php),接着就可以直接使用这些常量了。

使用这项技术有很多优势。首先,如果某些人仅仅浏览config.php文件,该页面是空白的。所以可以将config.php放到相同的文件中,并作为Web应用程序的根。第二,在任何编辑器中都可编辑,并且在一些编辑器中甚至具备语法着色及语法检查功能。

这项技术的缺点是,这是一个像INI文件一样的只读技术。将数据从此文件中提取出来是轻而易举的,但在该PHP文件中调整数据却很困难,在一些情况下甚至是不可能的。

下面的替代方法显示了如何编写在本质上既可读又可写的配置系统。

文本文件

前面的两个例子对于只读配置条目都是合适的,但对于既读又写的配置参数来说又如何呢?首先,看看清单6中的文本配置文件。

清单6.config.txt

#Myapplication'sconfigurationfile

Title=MyApp

TemplateDirectory=tempdir

这是同INI文件相同的文件格式,但我自己编写了辅助工具。为此,我创建了自己的Configuration类,如下所示。

清单7.text1.php

classConfiguration

{

private$configFile='config.txt';

private$items=array();

function__construct(){$this->parse();}

function__get($id){return$this->items[$id];}

functionparse()

{

$fh=fopen($this->configFile,'r');

while($l=fgets($fh))

{

if(preg_match('/^#/',$l)==false)

{

preg_match('/^(.*?)=(.*?)$/',$l,$found);

$this->items[$found[1]]=$found[2];

}

}

fclose($fh);

}

}

$c=newConfiguration();

echo($c->TemplateDirectory."\n");

?>

该代码首先创建了一个Configuration对象。该构造函数接下来读取config.txt并用解析过的文件内容来设置局部变量$items。

该脚本随后寻找TemplateDirectory,这并没有在对象中直接定义。因此,使用设置成'TemplateDirectory'的$id来调用神奇的__get方法,__get方法针对该键返回$items数组中的值。

这个__get方法特定于PHPV5环境,所以此脚本必须在PHPV5下运行。实际上,本文中所有的脚本都需要在PHPV5下运行。

当在命令行运行此脚本时,能看到下列结果:

%phptext1.php

tempdir

%

一切都在预料之中,该对象读取config.txt文件,然后为TemplateDirectory配置项获得正确的值。

但对于设置一个配置值,应该怎么做呢?在此类中建立一个新方法及一些新的测试代码,就能够得到这个功能,如下所示。

清单8.text2.php

classConfiguration

{

...

function__get($id){return$this->items[$id];}

function__set($id,$v){$this->items[$id]=$v;}

functionparse(){...}

}

$c=newConfiguration();

echo($c->TemplateDirectory."\n");

$c->TemplateDirectory='foobar';

echo($c->TemplateDirectory."\n");

?>

现在,有了一个__set函数,它是__get函数的“堂兄弟”。该函数并不为一个成员变量获取值,当要设置一个成员变量时,才调用这个函数。底部的测试代码设置值并打印出新值。

下面是在命令行中运行此代码时出现的结果:

%phptext2.php

tempdir

foobar

%

太好了!但如何能将它存储到文件中,从而将使这个改动固定下来呢?为此,需要写文件并读取它。用于写文件的新函数,如下所示。

清单9.text3.php

classConfiguration

{

...

functionsave()

{

$nf='';

$fh=fopen($this->configFile,'r');

while($l=fgets($fh))

{

if(preg_match('/^#/',$l)==false)

{

preg_match('/^(.*?)=(.*?)$/',$l,$found);

$nf.=$found[1]."=".$this->items[$found[1]]."\n";

}

else

{

$nf.=$l;

}

}

fclose($fh);

copy($this->configFile,$this->configFile.'.bak');

$fh=fopen($this->configFile,'w');

fwrite($fh,$nf);

fclose($fh);

}

}

$c=newConfiguration();

echo($c->TemplateDirectory."\n");

$c->TemplateDirectory='foobar';

echo($c->TemplateDirectory."\n");

$c->save();

?>

新的save函数巧妙地操作config.txt。我并没有仅用更新过的配置项重写文件(这样会移除掉注释),而是读取了这个文件并灵活地重写了$items数组中的内容。这样的话,就保留了文件中的注释。

在命令行运行该脚本并输出文本配置文件中的内容,能够看到下列输出。

清单10.保存函数输出

%phptext3.php

tempdir

foobar

%catconfig.txt

#Myapplication'sconfigurationfile

Title=MyApp

TemplateDirectory=foobar

%

构建可配置PHP应用程序有哪些方式

原始的config.txt文件现在被新值更新了。

XML配置文件

尽管文本文件易于阅读及编辑,但却不如XML文件流行。另外,XML有众多适用的编辑器,这些编辑器能够理解标记、特殊符号转义等等。所以配置文件的XML版本会是什么样的呢?清单11显示了XML格式的配置文件。

清单11.config.xml

tempdir

清单12显示了使用XML来装载配置设置的Configuration类的更新版。

清单12.xml1.php

classConfiguration

{

private$configFile='config.xml';

private$items=array();

function__construct(){$this->parse();}

function__get($id){return$this->items[$id];}

functionparse()

{

$doc=newDOMDocument();

$doc->load($this->configFile);

$cn=$doc->getElementsByTagName("config");

$nodes=$cn->item(0)->getElementsByTagName("*");

foreach($nodesas$node)

$this->items[$node->nodeName]=$node->nodeValue;

}

}

$c=newConfiguration();

echo($c->TemplateDirectory."\n");

?>

看起来XML还有另一个好处:代码比文本版的代码更为简洁、容易。为保存这个XML,需要另一个版本的save函数,将结果保存为XML格式,而不是文本格式。

清单13.xml2.php

...

functionsave()

{

$doc=newDOMDocument();

$doc->formatOutput=true;

$r=$doc->createElement("config");

$doc->appendChild($r);

foreach($this->itemsas$k=>$v)

{

$kn=$doc->createElement($k);

$kn->appendChild($doc->createTextNode($v));

$r->appendChild($kn);

}

copy($this->configFile,$this->configFile.'.bak');

$doc->save($this->configFile);

}

...

这段代码创建了一个新的XML文档对象模型(DocumentObjectModel,DOM),然后将$items数组中的所有数据都保存到这个模型中。完成这些以后,使用save方法将XML保存为一个文件。

使用数据库

最后的替代方式是使用一个数据库保存配置元素的值。那首先要用一个简单的模式来存储配置数据。下面是一个简单的模式。

清单14.schema.sql

DROPTABLEIFEXISTSsettings;

CREATETABLEsettings(

idMEDIUMINTNOTNULLAUTO_INCREMENT,

nameTEXT,

valueTEXT,

PRIMARYKEY(id)

);

这要求进行一些基于应用程序需求的调整。例如,如果想让配置元素按照每个用户进行存储,就需要添加用户ID作为额外的一列。

为了读取及写入数据,我编写了如图15所示的更新过的Configuration类。

清单15.db1.php

require_once('DB.php');

$dsn='mysql://root:password@localhost/config';

$db=&DB::Connect($dsn,array());

if(PEAR::isError($db)){die($db->getMessage());}

classConfiguration

{

private$configFile='config.xml';

private$items=array();

function__construct(){$this->parse();}

function__get($id){return$this->items[$id];}

function__set($id,$v)

{

global$db;

$this->items[$id]=$v;

$sth2=$db->prepare('DELETEFROMsettingsWHEREname=?');

$db->execute($sth2,$id);

if(PEAR::isError($db)){die($db->getMessage());}

$sth3=$db->prepare('INSERTINTOsettings(id,name,value)VALUES(0,?,?)');

$db->execute($sth3,array($id,$v));

if(PEAR::isError($db)){die($db->getMessage());}

}

functionparse()

{

global$db;

$doc=newDOMDocument();

$doc->load($this->configFile);

$cn=$doc->getElementsByTagName("config");

$nodes=$cn->item(0)->getElementsByTagName("*");

foreach($nodesas$node)

$this->items[$node->nodeName]=$node->nodeValue;

$res=$db->query('SELECTname,valueFROMsettings');

if(PEAR::isError($db)){die($db->getMessage());}

while($res->fetchInto($row)){

$this->items[$row[0]]=$row[1];

}

}

}

$c=newConfiguration();

echo($c->TemplateDirectory."\n");

$c->TemplateDirectory='newfoo';

echo($c->TemplateDirectory."\n");

?>

这实际上是一个混合的文本/数据库解决方案。请仔细观察parse方法。该类首先读取文本文件来获取初始值,然后读取数据库,进而将键更新为新的值。在设置一个值后,键就从数据库中移除掉,并添加一条具有更新过的值的新记录。

观察Configuration类如何通过本文的多个版本来发挥作用是一件有趣的事,该类能从文本文件、XML及数据库中读取数据,并一直保持相同的接口。我鼓励您在开发中也使用具有相同稳定性的接口。对于对象的客户机来说,这项工作具体是如何运行的是不明确的。关键的是对象与客户机之间的契约。

到此,相信大家对“构建可配置PHP应用程序的方式有哪些”有了更深的了解,不妨来实际操作一番吧!这里是创新互联建站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!


名称栏目:构建可配置PHP应用程序的方式有哪些-创新互联
文章路径:http://hbruida.cn/article/ceijej.html