澳门新葡萄京官网注册构建可配置PHP应用程序的正确方式

利用 PHP V5
的新语言特征,能够明显地坚实代码的可维护性和可相信性。通过翻阅本文,您将掌握怎么运用这个新特点将用
PHP V4 开拓的代码迁移到 PHP V5。 PHP V5 在 PHP V4
底蕴上做了重在改正。新语言特色使营造可信赖的类库和掩护类库尤其轻易。别的,重写规范库支持使
PHP 更适合其相近 Web 语系,比如 Java 编制程序语言。让大家来看有的 PHP
新的面向对象本性,并问询哪些将现存 PHP V4 代码迁移到 PHP V5。

本文比如表达了创办可布署 PHP
应用程序的二种方式。文中也查究了应用程序中完美的配置点,并在应用程序过分可配置和过为己甚密封时期寻求三个平衡点。

php贯彻八线程
服务器发送多少个央浼要兑现多进度要便于广大。只好采纳在cli情势。能够用在非正规场所,如邮件发送职务等。
财富的分享访谈使用了文本锁,实际不是很可相信,首假如为着能够在Windwos下利用,假如确实有不可贫乏可以伪造本人改用相应的复信号灯机制(那个扩张只可以用来xUNIX)。

首先,先来打探新语言特色及 PHP 的创立程序怎样改换了用 PHP V4
创制对象的点子。用 V5 的主见是要创设一种工业级语言用于 Web
应用程序开荒。那表示要打听 PHP V4 的限制,然后从别的语言中
收取已知优秀语言结构并将那些构造并入 PHP 中。

假定布置让别的人或商铺能够应用你的 PHP
应用程序,供给确定保证该程序是可配备的。最少,要允许客商以一种安全的秘籍设置数据库登陆及密码,进而使此中的资料不会对曾外祖父开。

实例
[php]
define(‘DIR_PHP_EXEC’, ‘php’);
define(‘DIR_MAIN_EXEC’, __FILE__);
define(‘DIR_TMP’, ‘/tmp’);
require_once(‘my_process.php’);

第三个也是最要害的新特色是针对类的办法和实例变量的拜谒爱护 ――
public、protected 和 private 关键字。
这些新特点使类设计人士可以确定保障对类的内在天性的调整,同有的时候候告诉类的使用者哪些类能够而哪些类不得以触发。

本文展现了两种用于存款和储蓄配置设置及编辑这个设置的手艺。此外,文中也为怎么因素要求设为可配备以至怎样幸免沦为配置过于依然配备不足的窘况提供了指点。

class pp extends my_process_base {
    public function run($param = null) {
        for ($i = 0; $i < 4; $i++) {
            echo “111 $paramn”;
            sleep(1);
        }
    }
}

在 PHP V4 中,全体代码都以 public 的。在 PHP V5中,类设计职员能够表明哪些代码是对表面可以见到的 (public卡塔尔而哪些代码仅对类内部可知 (private卡塔尔(قطر‎ 或仅对类的子类可以预知(protected卡塔尔国。若无那个访问调节,则在巨型团队中花费代码或将代码遍布为库的职业会受阻,因为那么些类的使用者很只怕采纳不当的章程或访谈应当为
private 成员变量的代码。

利用 INI 文件实行布署

init_my_process();
$obj = $GLOBALS[‘gal_obj_process_m’];
if ($obj->is_main()) {
    $obj->run_task(‘pp’, ‘a’);
    $obj->run_task(‘pp’, ‘b’);
    $obj->run_task(‘pp’, ‘c’);
    $obj->run_task(‘pp’, ‘d’);
    //$obj->run_task(‘pp’, ‘b’);
    $obj->set_max_run(10);
    $obj->run();
}

另叁个超大的新职能是生死攸关字 interface 和
abstract,那四个重大字允许进行协议编制程序。协议编制程序意味着一个类向另一个类提供一张公约 ―― 换言之:
“那是本身要做的专门的学问,你没有必要了然它是哪些产生的”。 完结 interface
的全数类都信守该左券。interface 的具备使用者都同意仅使用 interface
中钦赐的点子。abstract 关键字使得应用接口特别便于,小编稍后将加以证实。

PHP 内建了对安顿文件的支撑。那是经过 php.ini
文件那样的早先化文件编写制定达成的,在 php.ini
文件中定义了数据库连接超时或会话怎么着存款和储蓄等常量。假若愿意的话,能够在此个
php.ini 文件中为应用程序定制配置。为了求证,笔者将下列代码行增多到 php.ini
文件中。

[/php]

那三个首要特征 ―― 访谈调控和契约编制程序 ――
允许大型编码职员集体更流畅地动用大型代码库。那几个特征还使 IDE
能够提供更丰盛的言语智能性子集。本文不但表明了多少个迁移难题,并且还花了部分小时求证什么利用这一个新入眼语言特征。

myapptempdir=foo

进程管理类
[php]
/**
* @copyright 2007 movivi
* @author  徐智  <xzfred@gmail.com>
*
* $Id: getPage.php 11 2007-09-21 02:15:01Z fred $
*/
if (!defined(‘DIR_PHP_EXEC’)) define(‘DIR_PHP_EXEC’, ‘php’);
//if (!defined(‘DIR_MAIN_EXEC’)) define(‘DIR_MAIN_EXEC’, ”);
if (!defined(‘DIR_TMP’)) define(‘DIR_TMP’, ”);
/*****************************************************************************/
/* 初始化 */
define(‘CMD_MAIN_PROCESS_KEY’, ‘main_process_key’);
define(‘CMD_CHILD_PROCESS_NAME’, ‘child_process_name’);
define(‘CMD_CHILD_PROCESS_PARAM’, ‘child_process_param’);

访谈调整

接下来,笔者编写了二个小 PHP 脚本来读取那么些结构项,如清单 1 所示。

function init_my_process() {
    $GLOBALS[‘gal_obj_cmd’] = new my_cmd_argv();
    $key =
$GLOBALS[‘gal_obj_cmd’]->get_value(CMD_MAIN_PROCESS_KEY);
    $key = $key === false ? ” : $key;
    $GLOBALS[‘gal_obj_process_m’] = new my_process_m($key);
    if (!$GLOBALS[‘gal_obj_process_m’]->is_main())
$GLOBALS[‘gal_obj_process_m’]->run() ;
}

为了演示新语言特征,作者动用了一个名称为 Configuration
的类。那些大致的类中含有用于 Web 应用程序的配置项 ――
譬如,指向图片目录的门径。在地道的情形下,此消息将驻存在二个文件或数据Curry。清单1 显示了一个简化的本子。

清单 1. ini1.php

/**
* php多进程类
*
* 你需求从那几个目的世袭,然后实现您本身的run管理
*/
abstract class my_process_base {
    public function __construct($auto_run=true, $name=”) {
    }

清单 1. access.php4

<?php function get_template_directory() { $v = get_cfg_var(
“myapptempdir” ); return ( $v == null ) ? “tempdir” : $v; }

    public function __destruct() {
        echo “@endn”;
    }

?php class Configuration { var $_items = array();

echo( get_template_directory().”” ); ?>

    abstract public function run($param = null);
}

function Configuration() { $this-_items[ imgpath ] = images; }
function get( $key ) { return $this-_items[ $key ]; } }

当在命令行中启动这段代码时,获得如下结果:

class my_cmd_argv {
    private $cmd_argv = array();
    public function __construct() {
        $argv = $_SERVER[‘argv’];
        for ($i = 1; $i < count($argv); $i++) {
            $cmd = explode(‘=’, $argv[$i]);
            $this->cmd_argv[$cmd[0]] = isset($cmd[1]) ?
$cmd[1] : ”;
        }
    }

$c = new Configuration(); echo( $c-get( imgpath ).”” ); ?

% php ini1.php foo %

    public function get_key($key) {
        return isset($this->cmd_argv[$key]);
    }

那是一个通通规范的 PHP V4
类。成员变量保存配置项的列表,构造程序装入项,然后名称叫 get()的访问方法重回项的值。

太棒了。但为何不可能用规范的 INI 函数来获得 myapptempdir
配置项的值吗?笔者研商了一下,发今后大多动静下,定制配置项不可能利用那么些主意来赢得。但是,使用
get_cfg_var 函数却是能够访谈的。

    public function get_value($key) {
        return isset($this->cmd_argv[$key]) ?
$this->cmd_argv[$key] : false;
    }
}

运营脚本后,以下代码将显得在指令行中:

为使那么些艺术越发简便易行,将对变量的拜访封装在第贰个函数中,该函数使用安插键名及三个缺省值作为参数,如下所示。

/**
* php多进程管理类
* 能够在PHP中实现多进程管理,只限在控制台方式接纳
* 当前的时域信号完结机制选用文件措施
*
*/
class my_process_m {
    /**
     * @var array $task_list
     * 进程列表
     */
    private $task_list = array();
    private $lock_list = array();
    private $lock = null;
    private $is_main = false;
    private $max_run = 3600000;

% php access.php4 images %

清单 2. ini2.php

    private function release_lock($key = null) {
        $lock = &$this->lock_list;
        if (!is_null($key)) {
            $key = md5($this->build_lock_id($key));
            if (isset($lock[$key])) {
                if (is_resource($lock[$key][0]))
fclose($lock[$key][0]);
                unlink($lock[$key][1]);
                unset($lock[$key]);
            }
            return true;
        }

很好!这几个结果表示代码运营符合规律何况健康设定和读取了 imgpath
配置项的值。

function get_ini_value( $n, $dv ) { $c = get_cfg_var( $n ); return (
$c == null ) ? $dv : $c; }

        foreach ($lock as $k => $h) {
            if (is_resource($h)) fclose($h);
            unset($lock[$k]);
        }
        return true;
    }

将以此类调换为 PHP V5 的第一步是要将布局程序重命名。在 PHP V5中,最早化对象 的秘诀称为 __construct。本次小改造如下所示。

function get_template_directory() { return get_ini_value(
“myapptempdir”, “tempdir” ); }

    private function release_task($key = null) {
        $task = &$this->task_list;
        if (!is_null($key) && isset($task[$key])) {
            if (is_resource($task[$key])) pclose($task[$key]);
            unset($task[$key]);
        } else {
            foreach ($task as $k => $h) {
                if (is_resource($h)) pclose($h);
                unset($task[$k]);
            }
        }
        return true;
    }
           
    private function build_lock_id($key) {
        return DIR_TMP . DIRECTORY_SEPARATOR . $key . ‘_sem.lock’;
    }

清单 2. access1.php5

那是对哪些访谈 INI
文件的三个很好的统揽,所以,要是要采用一个两样的编写制定或将那么些 INI
文件存储到别的职责,就无需为转移大批量的函数而思前想后。

    protected function run_child_process() {
        $class =
$GLOBALS[‘gal_obj_cmd’]->get_value(CMD_CHILD_PROCESS_NAME);
        $param =
$GLOBALS[‘gal_obj_cmd’]->get_value(CMD_CHILD_PROCESS_PARAM);
        $param = $param == ” ? null :
unserialize(base64_decode(trim($param)));
        $obj = new $class();
        $obj->run($param);
        $this->task_list[] = $obj;
    }

?php class Configuration { var $_items = array();

本人不推荐使用 INI
文件作为应用程序的配置,那有八个理由。首先,尽管这么做较轻巧读取 INI
文件,但却大约不恐怕安全地写 INI
文件。所以那样做只切合于只读配置项。第二,php.ini
文件在服务器的持有应用程序上分享,所以自个儿以为特定于应用程序的配置项不应当写在该公文中。

    public function __construct($lock=”) {
        if ($lock === ”) {
            $this->is_main = true;
            $key = md5(uniqid()) . ‘_main.my_process’;
            $lock = array($key, $this->get($key));
        } else {
            $this->is_main = false;
            $lock = array($lock, 0);
        }
        $this->lock = $lock;
    }

function __construct() { $this-_items[ imgpath ] = images; }
function get( $key ) { return $this-_items[ $key ]; } }

需求对 INI 文件明白怎样吧?最重大的是如何重新设置 include
路线来增加配置项,如下所示。

    public function __destruct() {
        $this->release_lock();
        $this->release_task();
    }

$c = new Configuration(); echo( $c-get( imgpath ).”” ); ?

清单 3. ini3.php

    /**
     * 甘休全体进度
     *
     */
    public function stop_all() {
    }

此番修正并相当小。只是移至 PHP V5
约定。下一步是加上对类的访问调控以确认保障类的使用者不大概直接读写 $_items
成员变量。本次改变如下所示。

<?php echo( ini_get(“include_path”).”” ); ini_set(“include_path”,
ini_get(“include_path”).”:./mylib” ); echo(
ini_get(“include_path”).”” ); ?>

    /**
     * 是或不是是主进度
     *
     */
    public function is_main() {
        return $this->is_main;
    }

清单 3. access2.php5

在本例中,小编将本身的本地 mylib 目录增添到了 include
路线中,所以能够从该目录中 require PHP 文件,而没有须要将该路径增加到
require 语句中。

    /**
     * 是还是不是曾经存在一个活动实信号
     *
     * @param   string      $key
     * @return  bool       
     */
    public function exist($key) {
        return file_exists($this->build_lock_id($key));
    }

?php class Configuration { private $_items = array();

PHP 中的配置

    /**
     * 获取多个时限信号
     *
     * @param   string      $key    
     * @param   int         $max_acquire    最大央浼窒碍数量
     * @return mix 如若成功重回三个实信号ID
     *
     */
    public function get($key, $max_acquire=5) {
        $fn = $this->build_lock_id($key);
        if (isset($this->lock_list[md5($fn)])) return false;
        $id = fopen($fn, ‘a+’);
        if ($id) $this->lock_list[md5($fn)] = array($id, $fn);
        return $id;
    }

public function __construct() { $this-_items[ imgpath ] = images; }
public function get( $key ) { return $this-_items[ $key ]; } }

多如牛毛对于在 INI 文件中存款和储蓄配置条指标三个代表情势是利用二个大概的 PHP
脚本来保持数据。如下是一个样例。

    /**
     * 释放三个连续信号
     *
     * @param   string      $key    
     * @return  bool        借使成功重返三个随机信号true
     *
     */
    public function remove($key) {
        return $this->release_lock($key);
    }

$c = new Configuration(); echo( $c-get( imgpath ).”” ); ?

清单 4. config.php

    /**
     * 获取三个非时域信号
     *
     * @param string    $id         信号ID
     * @param bool      $block      是不是封堵
     */
    public function acquire($id, $block=false) {
        if ($block) {
            return flock($id, LOCK_EX);
        } else {
            return flock($id, LOCK_EX + LOCK_NB);
        }
    }

固然这一个指标的使用者都要直接待上访谈项阵列,访谈将被驳倒,因为该阵列被标志为
private。幸运的是,使用者开采 get(卡塔尔国 方法能够提供广受应接的读取权限。

<?php # Specify the location of the temporary directory #
$TEMPLATE_DIRECTORY = “tempdir”; ?>

    /**
     * 释放二个时限信号
     *
     */
    public function release($id) {
        flock($id, LOCK_UN);
    }
    public function run_task($process_name, $param=null) {
        $this->task_list[] = popen(DIR_PHP_EXEC . ‘ -f ‘ .
DIR_MAIN_EXEC . ‘ — ‘
            . CMD_CHILD_PROCESS_NAME . ‘=’ . $process_name . ‘ ‘
            . CMD_CHILD_PROCESS_PARAM . ‘=”‘ .
base64_encode(serialize($param)) . ‘” ‘
            . CMD_MAIN_PROCESS_KEY . ‘=”‘ . $this->lock[0] . ‘”
‘,
            ‘r’);
    }

为了印证如何利用 protected 权限,笔者索要另二个类,该类必需接二连三自
Configuration 类。作者把极度类称为
DBConfiguration,并假定该类将从数据库中读取配置值。此设置如下所示。

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

    public function run($auto_run = true) {
        if ($this->is_main) {
            $ps =
&$this->task_list;
            $max_run = &$this->max_run;
            $id = 0;
            do {
                //echo “process—————————————-:
n”;
                $c = 0;
                foreach ($ps as $k => $h) {
                    $c++;
                    $msg = fread($h, 8000);
                    if (substr($msg, -5, 4) ===
‘@end’)
{
                        echo “end process:[$k][$id] echo n{$msg}
n”;
                        $this->release_task($k);
                    } else {
                        echo “process:[$k][$id] echo n{$msg} n”;
                    }
                }
                sleep(1);
            } while ($auto_run && $id++ < $max_run && $c > 0);
        } else {
            $this->run_child_process();
        }
    }

清单 4. access3.php

清单 5. php.php

    public function set_max_run($max=1000) {
        $this->max_run = $max;
    }
}

?php class Configuration { protected $_items = array();

<?php require_once config.php;

public function __construct() { $this-load(); } protected function
load() { } public function get( $key ) { return $this-_items[ $key ];
} }

function get_template_directory() { global $TEMPLATE_DIRECTORY;
return $TEMPLATE_DIRECTORY; }

class DBConfiguration extends Configuration { protected function load()
{ $this-_items[ imgpath ] = images; } }

echo( get_template_directory().”” ); ?>

$c = new DBConfiguration(); echo( $c-get( imgpath ).”” ); ?

该代码首先包含配置文件,接着就足以平素利用那几个常量了。

那张项目清单展现了 protected 关键字的不错用法。基类定义了名字为 load(卡塔尔(قطر‎的办法。此类的子类将覆盖 load(卡塔尔国 方法把多少增进到 items 表中。load()方法对类及其子类是内部方法,由此该方式对持有外界使用者都不可以预知。假使主要字都以private 的,则 load(卡塔尔(قطر‎ 方法不能够被蒙蔽。

接纳那项本领有无数优势。首先,借使某个人偏偏浏览 config.php
文件,该页面是一无所有的。所以能够将 config.php 放到相仿的文本中,并视作 Web
应用程序的根。第二,在此外编辑器中都可编写制定,並且在部分编辑器中竟然具有语法着色及语法检查职能。

自己并不要命心爱此设计,不过,由于必得让 DBConfiguration
类能够访问项阵列而选取了此安排。笔者期望持续由 Configuration
类来完全维护项阵列,以便在增多任何子类后,那多少个类将不须求精晓怎么着体贴项阵列。作者做了以下改善。

那项技巧的老毛病是,那是叁个像 INI
文件一律的只读手艺。将数据以往文件中领到出来是一蹴即至的,但在该 PHP
文件中调节数据却非常不方便,在一部分情景下仍为不容许的。

清单 5. access4.php5

下边包车型大巴代替格局突显了什么编写在本质上既可读又可写的配备体系。

?php class Configuration { private $_items = array();

文件文件

public function __construct() { $this-load(); } protected function
load() { } protected function add( $key, $value ) { $this-_items[ $key
] = $value; } public function get( $key ) { return $this-_items[ $key
]; } }

眼下的五个例子对于只读配置条约都是恰到好处的,但对此既读又写的安插参数来说又怎么呢?首先,看看清单6 中的文本配置文件。

class DBConfiguration extends Configuration { protected function load()
{ $this-add( imgpath, images ); } }

清单 6. config.txt

$c = new DBConfiguration(); echo( $c-get( imgpath ).”” ); ?

# My applications configuration file Title=My App
TemplateDirectory=tempdir

今日,项阵列能够是 private 的,因为子类使用受保证的 add(卡塔尔方法将布置项加多到列表中。Configuration
类能够校正存款和储蓄和读取配置项的不二法门而无需思谋它的子类。只要 load(卡塔尔国 和
add(State of Qatar 方法以相近的方法运维,子类就相应不会出标题。

那是同 INI
文件一律的文件格式,但本人自个儿编辑了协理理工科程师具。为此,作者创制了上下一心的
Configuration 类,如下所示。

对此本人的话,扩张了访谈调控是考虑移至 PHP V5 的重要性缘由。难道就因为 Grady
Booch 说 PHP V5
是四大面向对象的语言之一么?不,因为自己曾经采取了二个职责来敬重 100KLOC
C++ 代码,在此些代码中全体办法和分子都被定义为 public
的。作者花了四天时间来消亡那个概念,并在去掉进程中,明显地收缩了错误数并加强了可维护性。为何?因为没有访谈调整,就不恐怕知道对象怎么着使用其它对象,也就不容许在不晓得要突破什么困难之处下做其余改造。使用
C++,起码本身还会有编译程序可用。PHP
未有配置编写翻译程序,由此那类采访调节变得更为首要。

清单 7. text1.php

协议编制程序

<?php class Configuration { private $configFile = config.txt; private
$items = array(); function __construct() { $this->parse(); } function
__get($id) { return $this->items[ $id ]; } function parse() { $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 ); } }

从 PHP V4 迁移到 PHP V5
时要动用的下一个关键特点是支撑通过接口、抽象类和形式开展公约编制程序。清单 6
显示了三个版本的 Configuration 类,在那类中 PHP V4
编码职员尝试了营造基本接口而素有不利用 interface 关键字。

$c = new Configuration();

清单 6. interface.php4

echo( $c->TemplateDirectory.”” ); ?>

?php class IConfiguration { function get( $key ) { } }

该代码首先创造了二个 Configuration 对象。该结构函数接下去读取 config.txt
并用剖判过的文本内容来安装有个别变量 $items。

class Configuration extends IConfiguration { var $_items = array();

该脚本随后寻找TemplateDirectory,那并不以往在指标中从来定义。因此,使用设置成
TemplateDirectory 的 $id 来调用玄妙的 __get 方法,__get
方法针对该键重临 $items 数组中的值。

function Configuration() { $this-load(); } function load() { } function
get( $key ) { return $this-_items[ $key ]; } }

这个 __get 方法特定于 PHP V5 条件,所以此脚本必得在 PHP V5
下运营。实际上,本文中享有的剧本都亟需在 PHP V5 下运作。

class DBConfiguration extends Configuration { function load() {
$this-_items[ imgpath ] = images; } }

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

$c = new DBConfiguration(); echo( $c-get( imgpath ).”” ); ?

% php text1.php tempdir %

清单开头于叁个微型 IConfiguration 类,该类定义全体 Configuration
类或派生类所提供的接口。此接口就要类与其抱有使用者之间定义合同。合同注脚了落实IConfiguration 的富有类必需配有 get(State of Qatar 方法並且 IConfiguration
的具有使用者都必需百折不摧仅使用 get(卡塔尔国 方法。

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

上边包车型客车这段代码是在 PHP V5 中运维的,但最棒应用提供的接口系统,如下所示。

但对于设置一个配置值,应该怎么做呢?在这里类中树立二个新点子及片段新的测验代码,就可以预知获得这些效率,如下所示。

清单 7. interface1.php5

清单 8. text2.php

?php interface IConfiguration { function get( $key ); }

<?php class Configuration { …

class Configuration implements IConfiguration { … }

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

class DBConfiguration extends Configuration { … }

function __set($id,$v) { $this->items[ $id ] = $v; } function
parse() { … } } $c = new Configuration(); echo(
$c->TemplateDirectory.”” ); $c->TemplateDirectory = foobar; echo(
$c->TemplateDirectory.”” ); ?>

$c = new DBConfiguration(); echo( $c-get( imgpath ).”” ); ?

当今,有了一个 __set 函数,它是 __get 函数的
“堂兄弟”。该函数并不为二个成员变量获取值,当要设置三个分子变量时,才调用那个函数。尾部的测量试验代码设置值并打字与印刷出新值。

单向,读者能够更驾驭地询问运维情况;另一面,单个类能够实现八个接口。清单8 展现了何等增加 Configuration 类来落实 Iterator 接口,对于 PHP
来讲,该接口是个中接口。

上边是在命令行中运转此代码时现身的结果:

清单 8. interface2.php5

% php text2.php tempdir foobar %

?php interface IConfiguration { … }

太好了!但怎么样能将它存款和储蓄到文件中,从而将使那一个退换固定下来吗?为此,要求写文件并读取它。用于写文件的新函数,如下所示。

class Configuration implements IConfiguration, Iterator { private
$_items = array();

清单 9. text3.php

public function __construct() { $this-load(); } protected function
load() { } protected function add( $key, $value ) { $this-_items[ $key
] = $value; } public function get( $key ) { return $this-_items[ $key
]; }

<?php class Configuration { …

public function rewind() { reset($this-_items); } public function
current() { return current($this-_items); } public function key() {
return key($this-_items); } public function next() { return
next($this-_items); } public function valid() { return (
$this-current() !== false ); } }

function save() { $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]].””; } else { $nf .= $l; } }
fclose( $fh ); copy( $this->configFile, $this->configFile..bak ); $fh
= fopen( $this->configFile, w ); fwrite( $fh, $nf ); fclose( $fh ); } }

class DBConfiguration extends Configuration { … }

$c = new Configuration(); echo( $c->TemplateDirectory.”” );
$c->TemplateDirectory = foobar; echo( $c->TemplateDirectory.”” );
$c->save(); ?>

$c = new DBConfiguration(); foreach( $c as $k = $v ) { echo( $k.” =
“.$v.”” ); } ?

新的 save 函数美妙地操作
config.txt。我并未仅用立异过的配置项重写文件,而是读取了这几个文件并灵活地重写了
$items 数组中的内容。那样的话,就保存了文件中的注释。

Iterator
接口使全体类都能够临近是其使用者的阵列。正如你在剧本末尾看见的那么,您能够选取foreach 运算符器重建议 Configuration 对象中的全部配置项。PHP V4
未有这种效果,但您能够在应用程序中经过各样措施利用此作用。

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

接口机制的帮助和益处是能够将合同连忙汇总在一起而无须落成任何方法。最后一段时期是兑现接口,您必得兑现全体钦命的法子。PHP
V5 中另三个有接济的新职能是
抽象类,使用抽象类可以轻巧地用一个基类完毕接口的着力部分,然后用该接口创造实体类。

清单 10. 保存函数输出

抽象类的另三个用处是为两个派生类创制三个基类,在这里些派生类中,基类决不会被实例化。举例,当
DBConfiguration 和 Configuration 同临时间存在时,则只可以利用
DBConfiguration。Configuration 类只是一个基类 ――
三个抽象类。因而,您能够利用 abstract 关键字免强该行为,如下所示。

% php text3.php tempdir foobar % cat config.txt # My applications
configuration file Title=My App TemplateDirectory=foobar %

清单 9. abstract.php5

原本的 config.txt 文件今后被新值更新了。

?php abstract class Configuration { protected $_items = array();

XML 配置文件

public function __construct() { $this-load(); } abstract protected
function load(); public function get( $key ) { return $this-_items[
$key ]; } }

纵然文本文件易于阅读及编辑,但却不比 XML 文件流行。别的,XML
有无数适用的编辑器,那几个编辑器能够清楚标识、特殊符号转义等等。所以安顿文件的
XML 版本会是哪些的呢?清单 11 展现了 XML 格式的安顿文件。

class DBConfiguration extends Configuration { protected function load()
{ $this-_items[ imgpath ] = images; } }

清单 11. config.xml

$c = new DBConfiguration(); echo( $c-get( imgpath ).”” ); ?

<?xml version=”1.0″?> <config> <Title>My App</Title>
<TemplateDirectory>tempdir</TemplateDirectory> </config>

现今,全数要将 Configuration
类型的指标实例化的尝试都会出错,因为系统感到该类是用空想来欺骗别人的还要破损。

项目清单 12 展现了利用 XML 来装载配置安装的 Configuration 类的更新版。

静态方法和成员

清单 12. xml1.php

PHP V5中的另四个重要的新功能是支撑对类使用静态成员和形式。通过接受这种效果,您能够运用流行的单例情势。这种情势对于
Configuration 类是那么些理想的,因为应用程序应当只有四个布署对象。

<?php class Configuration { private $configFile = config.xml; private
$items = array(); function __construct() { $this->parse(); } function
__get($id) { return $this->items[ $id ]; } function parse() { $doc
= new DOMDocument(); $doc->load( $this->configFile ); $cn =
$doc->getElementsByTagName( “config” ); $nodes =
$cn->item(0)->getElementsByTagName( “*” ); foreach( $nodes as $node )
$this->items[ $node->nodeName ] = $node->nodeValue; } }

清单 10 显示了 PHP V5 版的 Configuration 类作为二个单例。

$c = new Configuration(); echo( $c->TemplateDirectory.”” ); ?>

清单 10. static.php5

看起来 XML 还或者有另三个好处:代码比文本版的代码更为精短、轻便。为保留那么些XML,要求另三个版本的 save 函数,将结果保存为 XML 格式,实际不是文本格式。

?php class Configuration { private $_items = array();

清单 13. xml2.php

static private $_instance = null; static public function get() { if (
self::$_instance == null ) self::$_instance = new Configuration();
return self::$_instance; }

… function save() { $doc = new DOMDocument(); $doc->formatOutput =
true;

private function __construct() { $this-_items[ imgpath ] = images;
} public function __get( $key ) { return $this-_items[ $key ]; } }

$r = $doc->createElement( “config” ); $doc->appendChild( $r );

echo( Configuration::get()-{ imgpath }.”” ); ?

foreach( $this->items as $k => $v ) { $kn = $doc->createElement( $k
); $kn->appendChild( $doc->createTextNode( $v ) ); $r->appendChild(
$kn ); }

static
关键字有无数用法。当需求拜会单个项指标具有目的的一些全局数据时,请思索接收此关键字。

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

Magic Method

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

PHP V5 中的另一个超级大的新效率是支撑 magic
method,使用那几个办法使对象能够飞速改造对象的接口 ―― 举例,为
Configuration 对象中的每一个配置项增加成员变量。无须使用 get(State of Qatar方法,只要搜索一个非同小可项将它看做一个阵列,如下所示。

这段代码创建了三个新的 XML 文书档案对象模型,然后将 $items
数组中的全数数据都保存到这几个模型中。落成那些现在,使用 save 方法将 XML
保存为叁个文本。

清单 11. magic.php5

运用数据库

?php class Configuration { private $_items = array();

说起底的代替格局是选取几个数据库保存配置成分的值。那首先要用二个简约的方式来存款和储蓄配置数据。上边是一个简短的形式。

function __construct() { $this-_items[ imgpath ] = images; }
function __get( $key ) { return $this-_items[ $key ]; } }

清单 14. schema.sql

$c = new Configuration(); echo( $c-{ imgpath }.”” ); ?

DROP TABLE IF EXISTS settings; CREATE TABLE settings ( id MEDIUMINT NOT
NULL AUTO_INCREMENT, name TEXT, value TEXT, PRIMARY KEY ( id ) );

在本例中,小编创设了新的 __get(State of Qatar方法,只要使用者寻觅目的上的分子变量时即调用此方式。然后,方法中的代码将运用途阵列来查找值并重返该值,仿佛有八个特意用来该重大字的分子变量在当年同样。假定对象正是三个阵列,在本子的末段,您能够见到使用
Configuration 对象仿佛寻找 imgpath 的值同样轻松。

那必要进行部分依据应用程序要求的调度。比方,若是想让配置成分依照各类顾客进行仓库储存,就必要增多用户ID 作为额外的一列。

从 PHP V4 迁移到 PHP V5 时,应当要专一那一个在 PHP V4
中完全不可用的语言特色,还非得再一次验证类来查看能够怎么使用那些类。

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

异常

清单 15. db1.php

聊到底介绍 PHP V5中的新格外机制来收场本文。十分为思忖错误管理提供了一种全新的秘籍。全体程序都不可幸免地会转移错误
――
找不到文件、内部存款和储蓄器不足等等。假诺不接收十二分,则必得重返错误代码。请看下边的PHP V4 代码。

<?php require_once( DB.php ); $dsn =
mysql://root:password@localhost/config; $db = DB::Connect( $dsn, array()
); if (PEAR::isError($db)) { die($db->getMessage()); }

清单 12. file.php4

class Configuration { 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; $sth1 = $db->prepare( DELETE
FROM settings WHERE name=? ); $db->execute( $sth1, $id ); if
(PEAR::isError($db)) { die($db->getMessage()); } $sth2 =
$db->prepare(INSERT INTO settings ( id, name, value ) VALUES ( 0, ?,
? ) ); $db->execute( $sth2, array( $id, $v ) ); if
(PEAR::isError($db)) { die($db->getMessage()); } }

?php function parseLine( $l ) { // … return array( error = 0, data =
array() // data here ); }

function parse() { global $db; $doc = new DOMDocument(); $doc->load(
$this->configFile ); $cn = $doc->getElementsByTagName( “config” );
$nodes = $cn->item(0)->getElementsByTagName( “*” ); foreach( $nodes
as $node ) $this->items[ $node->nodeName ] = $node->nodeValue; $res
= $db->query( SELECT name,value FROM settings ); if
(PEAR::isError($db)) { die($db->getMessage()); } while(
$res->fetchInto( $row ) ) { $this->items[ $row[0] ] = $row[1]; }
} }

function readConfig( $path ) { if ( $path == null ) return -1; $fh =
fopen( $path, r ); if ( $fh == null ) return -2;

$c = new Configuration(); echo( $c->TemplateDirectory.”” );
$c->TemplateDirectory = new foo; echo( $c->TemplateDirectory.”” );
?>

while( !feof( $fh ) ) { $l = fgets( $fh ); $ec = parseLine( $l ); if (
$ec[error] != 0 ) return $ec[error]; }

这实际是三个混合的文书/数据库解决方案。请留意考察 parse
方法。该类首先读取文本文件来博取初始值,然后读取数据库,从而将键更新为新型的值。在设置二个值后,键就从数据库中移除掉,并增添一条具备更新过的值的新记录。

fclose( $fh ); return 0; }

观测 Configuration
类怎样通过本文的多少个本子来发挥成效是一件有趣的事,该类能从文本文件、XML
及数据库中读取数据,并一向维持同等的接口。作者激励你在开采中也采用具备同等稳定性的接口。对于指标的客户机来讲,那项职业实际是哪些运营的是不明确的。关键的是目的与客商机之间的左券。

$e = readConfig( myconfig.txt ); if ( $e != 0 ) echo( “There was an
error (“.$e.”)” ); ?

怎样是安排及如何安顿

这段正式的公文 I/O
代码将读取三个文本,检索一些数码,并在蒙受任何不那个时候回来错误代码。对于这几个剧本,笔者有多少个难题。第3个是错误代码。那几个错误代码的含义是什么?要搜索这一个错误代码的意义,则必需创制另一个体系将这几个错误代码映射到有含义的字符串中。第一个难题是
parseLine
的回到结果十三分复杂。笔者只必要它回到数据,但它实际上必需再次来到错误代码 和
数据。大非常多程序猿平时偷懒,仅再次回到数据,而忽视掉错误,因为错误很难管理。

在结构过多的布局选项与构造不足间找一个切合的中间点是一件困难的事。能够料定的是,任何数据库配置都应该是可安排的。除此而外,作者还会有一点点骨干的引荐配置项。

事项清单 13 展现了接受特别时期码的传诵一时程度。

在高等设置中,每二个特色都应该有一个独自的启用/禁止使用选项。依照其对应用程序的首要来允许或剥夺那么些接受。比如,在一个Web
论坛应用程序中,延时特点在缺省气象下是启用的。但电子邮件通告在缺省景色下却是禁用的,因为那如同要求定制。

清单 13. file.php5

顾客分界面选项全应该安装到三个职位上。分界面包车型地铁布局全应该设置到一个十足地点上。小编显然地提议不用将字体、颜色或样式条目款项钦命为布局项。那几个都应当通过层叠样式表来设置,且布局种类应该钦点使用哪个
CSS 文件。CSS
是设置字体、样式、颜色等等的一种有效且灵活的不二诀要。有过多可观的 CSS
工具,您的应用程序应该很好地使用 CSS,并不是思考自行设置标准。

?php function parseLine( $l ) { // Parses and throws and exception when
invalid return array(); // data }

在每叁个性子中,笔者引入设置 3 到 拾个布局选项。这么些配置选项应该以一种意义不言自明的格局命名。假若布署选项能够通过
UI 设置,在文件文件、XML
文件及数据库中的选项名称应当平昔同分界面成分的标题相关。别的,那一个选项全应该有醒指标缺省值。

function readConfig( $path ) { if ( $path == null ) throw new Exception(
bad argument );

如上所述,下边那么些接收应该是可计划的:电子邮件地址、CSS
所使用的东西、从文件中引用的系统财富的岗位以至图片成分的文本名。

$fh = fopen( $path, r ); if ( $fh == null ) throw new Exception( could
not open file );

对于图片成分,您大概想要成立一个名称叫皮肤
的独立的布局文件类型,该品种中包蕴了对安顿文件的设置,包涵 CSS
文件的位置、图形的地点及那个项目的事物。然后,让客户在各个肌肤文件中张开分选。那使得对应用程序外观和感觉的宽广更退换得轻便。那也同等为用户提供了八个空子,使应用程序能够在分化的付加物安装间转移皮肤。本文并不分包那个皮肤文件,但你在这里边学到的基本功知识将会使对皮肤文件的支撑变得更其简便易行。

while( !feof( $fh ) ) { $l = fgets( $fh ); $ec = parseLine( $l ); }

结束语

fclose( $fh ); }

可配置性对于其它 PHP
应用程序来讲都以首要的一个片段,一初步就应该改成企划的中坚部分。我期待本文能够对你实现配置构造提供一些救助,并对应该允许什么样的配备选项有所教导。

try { readConfig( myconfig.txt ); } catch( Exception $e ) { echo( $e );
} ?

自身不必思考错误代码难点,因为十三分中含有了错误的表明性文字。小编也无需思考怎样追踪从
parseLine
重临的错误代码,因为倘诺现身错误,该函数将只抛出一个不当。仓库将拉开至近来的
try/catch 块,该块坐落于脚本的最底层。

格外机制将深透改造编写代码的办法。您不要管理令人讨厌的错误代码和照耀,能够将精力聚集在要拍卖的荒谬上。那样的代码更便于阅读、维护,并且自身要说,以致要慰勉你增多错误管理机制,它常常都能带来收益。

结束语

新的面向对象特性和极其管理的扩张为将代码从 PHP V4 迁移到 PHP V5
提供了强盛的理由。正如您所见,进级历程并轻巧。扩大到 PHP V5
的语法认为就好像 PHP 相似。是的,那个语法来自诸如 Ruby
之类的言语,但本人感觉它们合作得不行好。何况那些语言将 PHP
的范围从一种用于迷你站点的脚本语言扩充为可用来完毕公司级应用的言语。

发表评论

电子邮件地址不会被公开。 必填项已用*标注