在 FleaPHP 应用程序中使用第三方组件
时间:2008-04-12 来源:qeeify
在使用 FleaPHP 开发应用程序时,开发者可以很容易得运用第三方组件。本文就几种典型的运用方式做了详细说明。
本文原始网址:
http://www.dualface.com/blog/?p=449
在 FleaPHP 中使用 PEAR 组件
PEAR 是一个庞大的 PHP 组件库,提供了各种各样的组件供开发者选用。虽然大多数 PEAR 组件只需要在程序中 include 进来即可使用。但少数 PEAR 组件依赖于 PEAR 提供的错误处理机制。
对于这类组件,我们希望能够用 FleaPHP 的错误处理机制统一处理。以便开发者能够获得一致性的错误处理流程。
Cache_Lite 是 PEAR 中一个非常出色的缓存组件,可以提供快速、可靠的缓存服务。但这个组件在发生错误时会调用 PEAR 的错误处理机制。而我们希望在发生错误时,Cache_Lite 能够抛出一个异常。
改造过程很简单,编写一个如下的类即可:
?php
require 'Cache_Lite.php';
class Helper_CacheLite extends Cache_Lite
{
function raiseError($msg, $code)
{
__THROW(new FLEA_Exception($msg, $code));
}
}
?>
使用时:
?php
FLEA::loadClass('Helper_CacheLite');
$cache = new Helper_CacheLite($options);
?>
我们可以更进一步,完善这个 Helper_Cache_Lite,让它更方便、更完善。
?php
/**
* 根据应用程序设置确定 Cache_Lite 文件所在位置
*/
do {
if (PHP5) {
if (class_exists('Cache_Lite', false)) { break; }
} else {
if (class_exists('Cache_Lite')) { break; }
}
$dir = FLEA::getAppInf('cacheLiteDir');
$filename = $dir . '/Cache_Lite.php';
require($filename);
} while (false);
class FLEA_Helper_CacheLite extends Cache_Lite
{
/**
* 新的构造函数使用一个选项名从应用程序设置中读取构造 Cache_Lite 对象需要的参数
*/
function FLEA_Helper_CacheLite($optionName = 'cacheLiteConfig')
{
$options = (array)FLEA::getAppInf('cacheLiteConfig');
parent::Cache_Lite($options);
}
function raiseError($msg, $code)
{
__THROW(new FLEA_Exception($msg, $code));
}
}
?>
新的代码使用前要做一些准备工作。首先是指定应用程序设置 cacheLiteDir 为 Cache_Lite.php 所在路径,其次是将构造 Cache_Lite 时需要的参数也添加到应用程序设置中,例如:
?php
require 'FLEA.php';
// 指定 Cache_Lite.php 所在目录
FLEA::setAppInf('cacheLiteDir', dirname(__FILE__) . '/3rd/Cache_Lite');
// 指定一个 Cache_Lite 配置
FLEA::setAppInf('cacheLiteConfig', array(
'cacheDir' => dirname(__FILE__) . '/_Cache',
'caching' => true,
'lifeTime' => 900,
'fileNameProtection' => true,
'automaticSerialization' => true,
));
// 指定另一个 Cache_Lite 配置
FLEA::setAppInf('cacheLiteConfig2', array(
'cacheDir' => dirname(__FILE__) . '/_Cache2',
'caching' => true,
'lifeTime' => 300,
'fileNameProtection' => true,
'automaticSerialization' => true,
));
// 载入 FLEA_Helper_CacheLite 类定义
FLEA::loadClass('FLEA_Helper_CacheLite');
// 使用不同的参数构造两个不同的 Cache_Lite 对象
$cache1 = new FLEA_Helper_CacheLite('cacheLiteConfig');
$cache2 = new FLEA_Helper_CacheLite('cacheLiteConfig2');
?>
从上面的代码可以看出,只需要在 index.php 中(基于 FleaPHP 的单一入口应用程序)指定好设置,或者在配置文件中指定好设置。我们构造 Cache_Lite 对象时就不用把构造参数复制多份了,仅仅指定一个选项名即可。
同时,如果 Cache_Lite 使用中出现错误,会抛出一个可捕获的异常。此时,改造过的 Cache_Lite 已经完全不再依赖 PEAR 核心库了。
在 FleaPHP 中使用 Zend Framework 组件
在 FleaPHP 应用程序中使用 Zend Framework 组件不需要额外的封装,只需要单独做好两项准备工作。
第一步是将需要的 ZF 组件文件复制到项目目录中。由于 ZF 的各个组件之间有依赖关系,要仔细检查一下源代码,看看是不是需要的文件都复制了。当然了,图省事可以把整个 ZF 的目录都复制到项目中来。
第二步是修改 php.ini,将 ZF 文件的目录添加到 include_path 选项中。或者在 index.php 中使用如下的代码在运行时设置 include_path:
ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . dirname(__FILE__) . '/Zend');
完成上面两项准备工作后,就可以随意使用 ZF 的组件了:
?php
..... 初始化代码 .....
$tableSendmailQueue = FLEA::getSingleton('Table_SendmailQueue');
/* @var $tableSendmailQueue Table_SendmailQueue */
$rowset = $tableSendmailQueue->findAll(null, 'created ASC', 100);
require_once 'Zend/Mail.php';
foreach ($rowset as $row) {
$mail = new Zend_Mail('utf-8');
$mail->setFrom($row['sender'])
->addTo($row['recipients'])
->setSubject($row['subject'])
->setBodyHtml($row['body'])
->send();
unset($mail);
}
?>
由于 Zend Framework 在类的命名、目录结构上,和 FleaPHP 一样的机制,所以还可以用 FleaPHP 的各种方法来直接载入 ZF 对象或者管理 ZF 对象。其次,FleaPHP 也可以直接处理 ZF 抛出的异常。
用第三方组件替换 FleaPHP 自带的组件
FleaPHP 是一个开放的框架,允许开发者灵活的选择第三方库来搭建自己的应用程序。大多数第三方组件,只需要简短的编码即可和 FleaPHP 融合到一起。并且配合 FleaPHP 的扩展机制,可以在不修改应用程序的情况下,直接用第三方组件替换 FleaPHP 自带的组件。
下面笔者演示如何用 Zend Framework 中的 Zend_Log 组件来替换 FLEA_Log 组件,同时达到应用程序代码完全不用修改的目标。
Zend_Log 和 FLEA_Log 功能类似,但 FLEA_Log 提供了一个 log_message() 全局函数,方便开发者随时添加日志信息。其次,Zend_Log::log() 方法要求的参数个数及类型都和 FLEA_Log::appendLog() 不同,这也是我们需要处理的地方。
下面先编写 Zend_Log 的适配器,以便 Zend_Log 能够支持 FLEA_Log 要求的接口。
?php
class FLEA_Log_Adapter_Zend extends Zend_Log
{
/**
* 用于将字符串形式的日志优先级转换为对应的常量值
*/
protected $_prioritiesText = array();
/**
* 覆盖构造函数,将 Zend_Log 内部的优先级数据转换为容易查找的格式
*/
public function __construct($writer = null)
{
if ($writer == null) {
// 当没有指定 $writer 参数时,使用应用程序设置 logWriterClass 指定的对象
$writerClass = FLEA::getAppInf('logWriterClass');
if ($writerClass) {
FLEA::loadClass($writerClass);
$writer = new $writerClass();
}
}
parent::__construct($writer);
$this->_prioritiesText = array_flip($this->_priorities);
}
/**
* 覆盖 Zend_Log::addPriority() 方法,以便在添加新的优先级后更新内部数组
*/
public function addPriority($name, $priority)
{
parent::addPriority($name, $priority);
$this->_prioritiesText = array_flip($this->_priorities);
}
/**
* 覆盖 Zend_Log 的 log() 方法
*/
public function log($message, $priority = 'INFO', $title = '')
{
/**
* Zend_Log::log() 的 $priority 参数是整数,
* 而 FLEA_Log::appendLog() 该参数是字符串,
* 因此需要转换一下。
*/
$priority = strtoupper($priority);
$i = isset($this->_prioritiesText[$priority]) ?
$this->_prioritiesText[$priority] :
$this->_prioritiesText['INFO'];
if ($title != '') {
$message = $title . ' ' . $message;
}
parent::log($message, $priority);
}
}
/**
* 补上 Zend_Log 没有的 log_message() 函数
*/
function log_message($message, $priority = 'INFO', $title = '')
{
static $log = null;
if ($log === null) {
$log = FLEA::getSingleton('FLEA_Log_Adapter_Zend');
}
$log->log($message, $priority, $title);
}
?>
不过这个适配器还不能马上工作,我们还得提供适当的 writer 给它(实际上是 Zend_Log 需要)。
我们可以自己实现一个 Zend_Log_Writer_Abstract 继承类,也可以将 Zend Framework 中现有的 writer 再简单封装一下:
?php
class FLEA_Log_Writer_Stream extends Zend_Log_Writer_Stream
{
public function __construct()
{
$streamOrUrl = FLEA::getAppInf('logWriterStreamUrl');
$mode = FLEA::getAppInf('logWriterStreamMode');
parent::__construct($streamOrUrl, $mode);
}
}
?>
现在准备工作已经完成了,只需要修改下面几项应用程序设置即可让我们的应用程序就会使用 Zend_Log 来保存日志了:
logProvider = 'FLEA_Log_Adapter_Zend'
logWriterClass = 'FLEA_Log_Writer_Stream'
logWriterStreamUrl = '/var/log/app.log'
logWriterStreamMode = 'a'
上面的所有操作都不需要修改应用程序的代码,显著降低了更换组件的成本和风险。
总结
从上面提到的实际运用可以看到,要在 FleaPHP 中使用第三方组件有两种方式:简单的直接引用和完全集成。
对于少量的使用,只要将需要的组件文件 include 进来就可以了。而要充分发挥 FleaPHP 高度可扩展能力,或者用第三方组件替换应用程序中已经使用的组件,则需要进行一些额外工作。但这些额外工作的好处就是可以获得一个完全融合到 FleaPHP 体系中的组件,为开发者提供了一致的接口和开发体验。这一点对于开发大规模应用程序来说非常重要。
要将第三方组件完全集成到 FleaPHP 体系中,就必须充分利用应用程序设置这个概念。简单来说,应用程序设置类似 Windows 注册表,其中包含了应用程序、框架运行时需要的所有设置。而这些设置的来源既可以是配置文件,也可以是数据库,还可以在运行时动态修改。
通过将应用程序结构的组合方式(各个组件之间的搭配)写入配置文件,应用程序可以获得出色的可扩展能力和灵活性,这比起用一大堆代码来组合各个组件要合理得多。曾经有许多开发者争论什么叫做可扩展能力,我认为可扩展能力最重要的体现就是能够以最小的代价改变应用程序的组件。而不是用有多少个类、多么复杂的对象体系来体现的。
原文地址:
http://qeeify.com/index.php/2008/03/22/hwoto-use-external-component.html
更多信息,请访问 FleaPHP/QeePHP 开源开发框架官方网站:
http://www.fleaphp.org/
。
相关阅读 更多 +
排行榜 更多 +