一. 单例模式(Singleton) 如果应用程序每次包含且仅包含一个对象,那么这个对象就是一单例. 用来替代全局变量. 复制代码 代码如下: <?php require_once("DB.php"); class DatabaseConnection{ <STRONG><SPAN style="COLOR: #ff0000">public static function get()</SPAN></STRONG>{ static $db = null; if ( $db == null ) $db = new DatabaseConnection(); return $db; } private $_handle = null; <STRONG><SPAN style="COLOR: #ff0000">private function __construct()</SPAN></STRONG> { $dsn = 'mysql://root:[email protected]/photos'; $this->_handle =& DB::Connect( $dsn, array() ); } public function handle() { return $this->_handle; } } print( "Handle = ".DatabaseConnection::get()->handle()."\n" ); print( "Handle = ".DatabaseConnection::get()->handle()."\n" ); ?> 二.工厂方法模式(factory method)要解决的问题: 1>在代码运行时候才知道要生成的对象类型; 2>对象类型可能要扩充新产品类型; 3>每个产品类型都可以定制特定的功能;工厂方法模式把创建者类与要生产的产品类分离.创建者是一个工厂类,其中定义了用于生成产品对象的类方法.如果没有提供默认实现,就由创建者类的子类来执行实例化.一般情况下,就是每个创建者类的子类实例化一个相应的产品子类.工厂模式的优点就在创建对象上。 它的任务就是把对象的创建过程都封装起来,然后返回一个所需要的新类。想改变对象的结构和建立对象的方式,只需选择对象工厂,对代码的改变只需要一次就够了。( 工厂模式的功能是如此强大, 它处于是应用的底层, 所以在许多其余的复杂模式和应用中它会不停地出现。)不同处理对象,内部自动分流处理,但对用户来说,只有一个方法,简单方便 使用接口方式实践工厂模式的例子: 复制代码 代码如下: interface Hello{ function say_hello(); } class English implements Hello{ public function say_hello(){ echo "Hello!"; } } class Chinese implements Hello{ public function say_hello(){ echo "你好"; } } class speak{ public static function factory($type){ if($type == 1) $temp = new English(); else if($type == 2) $temp = new Chinese(); else{ die("Not supported!"); } return $temp; } } $test = Speak::factory(1); $test->say_hello(); 在<深入浅出设计模式>中,上面的被称为简单工厂模式,因为这个工厂必须能分辨要生产的全部产品.如果有新的产品,必须对工厂进行对应修改,增加相应的业务逻辑或判断.简单工厂模式的一个标志就是静态方法实现工厂生产功能.(不简单的)工厂方法模式: 工厂方法是抽象类或接口,具体工厂实现这个方法(接口),让使用者调用以创建具体产品对象(每一个产品都有对应的具体工厂)下面是重写的hello 复制代码 代码如下: //抽象工厂 interface Speaker{ function assignSpeaker(); } //具体工厂1 class EnglishSpeaker implements Speaker{ public function assignSpeaker(){ return new English(); } } //具体工厂2 class ChineseSpeaker implements Speaker{ public function assignSpeaker(){ return new Chinese(); } } //抽象产品 interface Hello{ function say_hello(); } //具体产品1 class English implements Hello{ public function say_hello(){ echo "Hello!"; } } //具体产品2 class Chinese implements Hello{ public function say_hello(){ echo "你好"; } } 使用: 复制代码 代码如下: if(!empty($_GET['t'])){ switch($_GET['t']){ case 1: $temp=new EnglishSpeaker(); break; case 2: $temp=new ChineseSpeaker(); break; } $man=$temp->assignSpeaker(); $man->say_hello(); } 三.抽象工厂模式(Abstract Factory)产品族;每个实体工厂负责一个产品族(1,2...)的产品, 而每个产品族又划分出几个不同类别(A,B...)单从某一个实体工厂看,其实就是一个工厂方法模式 如果上面的hello例子,又多出来表达方式,正常和歌唱式表达(2个产品族) 复制代码 代码如下: //抽象工厂 abstract class Speaker{ const NORMAL =1; const SING =2; abstract function assignSpeaker($flag_int); } //具体工厂1 class EnglishSpeaker extends Speaker { public function assignSpeaker($flag_int){ switch($flag_int){ case self::NORMAL: return new NormalEnglish(); break; case self::SING: return new SingEnglish(); break; } } } //具体工厂2 class ChineseSpeaker extends Speaker{ public function assignSpeaker($flag_int){ switch($flag_int){ case self::NORMAL: return new NormalChinese(); break; case self::SING: return new SingChinese(); break; } } } //抽象产品 interface Hello{ function say_hello(); } //具体产品A1 class NormalEnglish implements Hello{ public function say_hello(){ echo "Hello!"; } } //具体产品B1 class NormalChinese implements Hello{ public function say_hello(){ echo "你好!"; } } //具体产品A2 class SingEnglish implements Hello{ public function say_hello(){ echo "Oh, jingle bells, jingle bells, Hello! Hello! Hello!"; } } //具体产品B2 class SingChinese implements Hello{ public function say_hello(){ echo "叮叮当,叮叮当, 你好!你好!你好!"; } } 使用: 复制代码 代码如下: //根据程序的业务逻辑确定具体工厂 switch($_GET['language']){ case 1: $temp=new EnglishSpeaker(); break; case 2: $temp=new ChineseSpeaker(); break; } //根据程序的业务逻辑确定具体产品,无需关心是哪个具体工厂了,维护性提高 $man=$temp->assignSpeaker( $_GET['style']); //使用产品,无需关心是哪个具体产品 $man->say_hello(); 四.原型模式(Prototype) 使用clone 来复制已存在的具体产品,

一:队列的概念、数据结构队列(Queue)是运算受到限制的一种线性表。只允许在表的一端进行插入,而在另一端进行删除元素的线性表。队尾(rear)是允许插入的一端。队头(front)是允许删除的一端。空队列是不含元素的空表。假设有个队列Q=(a1,a2,…,an),则a1为队头元素,an为队尾元素。元素入队的次序为a1,a2,…,an,而出队的次序为a1,a2,…,an。可见队列的操作是按照先进先出的原则进行的。其他详细的介绍请在网上搜索很多资料。二:PHP的队列在PHP中队列以数组的形式表现。数组中的第一个元素作为队头,最后一个元素作为队尾,这样就可以操作这个队列了。结果就是网上有很多封装好的类,可以直接使用。array_push:将一个或多个单元压入数组的末尾(入栈)array_unshift:在数组开头插入一个或多个单元array_pop:将数组最后一个单元弹出(出栈)array_shift:将数组开头的单元移出数组三:Ruby StarlingStarling是一个支持MemCache协议的轻量级持久化服务器。Starling是让创建网络访问队列或者多个队列异常简单,也就是说多点和多台机器间的异步工作进程。它是著名微博客网站Twitter开发用来处理大量的队列消息,以及保持服务的响应。Starling已经在生产环境中使用,不仅是Twitter在使用,FiveRuns同样在使用。FiveRuns甚至还根据自己的应用做了改进。Starling和Memcache使用的是一个协议只是端口不一样。Starling使用的是22122端口,Memcache使用的是11211端口。Rubytar xzvf ruby-1.9.1-p0.tar.gzcd ruby-1.9.1-p0./configure --prefix=/usr/local/huiyangrubymake make install Gemtar -zxvf rubygems-1.3.6.tgzcd rubygems-1.3.6ruby setup.rb Starlinggem install memcache-client starlingstarlingstarling & //后台执行starling_top //查看PS信息接下来你就可以使用队列做自己的事情啦。Starling和Memcache用法一样,两者配合处理更佳。使用Memcache::addServer可以建立一个memcache连接池。他不同于connect与pconnect他是在有请求是才连接,无则端口连接。Memcache::connect -- 打开一个到Memcache的连接。Memcache::pconnect -- 打开一个到Memcache的长连接。Memcache::close -- 关闭一个Memcache的连接。Memcache::set -- 保存数据到Memcache服务器上。Memcache::get -- 提取一个保存在Memcache服务器上的数据。Memcache::replace -- 替换一个已经存在Memcache服务器上的项目(功能类似Memcache::set)。Memcache::delete -- 从Memcache服务器上删除一个保存的项目。Memcache::flush -- 刷新所有Memcache服务器上保存的项目(类似于删除所有的保存的项目)。Memcache::getStats -- 获取当前Memcache服务器运行的状态。四:张宴作品HTTPSQSHTTPSQS(HTTP Simple Queue Service)是一款基于 HTTP GET/POST 协议的轻量级开源简单消息队列服务,使用 Tokyo Cabinet 的 B+Tree Key/Value 数据库来做数据的持久化存储。有兴趣的可以看看网址:http://blog.s135.com/httpsqs_1_2/五:队列的应用队列可以很好地异步处理数据传送和存储,当你频繁地向数据库中插入数据、频繁地向搜索引擎提交数据,就可采取队列来异步插入。另外,还可以将较慢的处理逻辑、有并发数量限制的处理逻辑,通过消息队列放在后台处理,例如FLV视频转换、发送手机短信、发送电子邮件等。

在计算机科学中,正则表达式用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。在WEB开发中,正则表达式通常用来检测、查找替换某些符合规则的字符串,如检测用户输入E-mai格式是否正确,采集符合规则的页面内容等等。今天我们分别用PHP和Javscript向大家介绍WEB开发中最常用最实用的正则表达式及其用法,正则表达式是一门学科,不可能使用一篇文章来讲解完,理论的东西网上很多,有兴趣的同学可以搜一大把。不过你也许没必要去埋头学习琢磨不透的正则表达式,看本文和实例给您呈现常用、实用的正则表达式。PHP常用表达式用法:1.匹配正整数:/^[1-9]\d*$/2.匹配非负整数(正整数+0):/^\d+$/3.匹配中文:/^[\x{4e00}-\x{9fa5}]+$/u4.匹配Email:/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/5.匹配网址URL:(((f|ht){1}(tp|tps)://)[[email protected]:%_\+.~#?&//=]+)6.匹配字母开头,5-16字符,字母数字下划线:/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/7.匹配数字,字母,下划线,中文:/^[\x{4e00}-\x{9fa5}A-Za-z0-9_]+$/u8.匹配中国邮政编码:/^[1-9]\d{5}$/9.匹配IP地址:/\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/10.匹配中国大陆身份证:/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}(\d|x|X)$/PHP正则验证字符串方法举例:复制代码 代码如下:$str = "中文啊"; $preg = "/^[\x{4e00}-\x{9fa5}]+$/u"; //匹配中文 if(preg_match($preg,$str,$arr)){      $msg = '匹配成功!'; }else{      $msg = '匹配失败!'; } echo $msg; Javascript常用表达式用法1.匹配正整数:/^[0-9]*[1-9][0-9]*$/2.匹配非负整数(正整数+0):/^\d+$/3.匹配中文:/^[\u4e00-\u9fa5]/4.匹配Email:/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/5.匹配网址URL:/^(f|ht){1}(tp|tps):\/\/([\w-]+\.)+[\w-]+(\/[\w- ./?%&=]*)?/6.匹配字母开头,5-16字符,字母数字下划线:/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/7.匹配数字,字母,下划线,中文:/^[\u4e00-\u9fa5A-Za-z0-9_]+$/8.匹配中国邮政编码:/^[1-9]\d{5}$/9.匹配IP地址:/\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/10.匹配中国大陆身份证:/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}(\d|x|X)$/Javascript正则验证字符串方法举例:复制代码 代码如下: var str = "[email protected]"; var preg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/; //匹配Email if(preg.test(str)){     var msg = "匹配成功"; }else{     var msg = "匹配失败!

大家可以通过下面这一段代码,来具体了解PHP批量上传图片的具体方式。我们在学习PHP的时候,肯定是要从实际操作中慢慢积累经验,以巩固我们所学到的知识,逐渐的加强我们的编程水平。•PHP保护文件系统的具体代码分享•PHP保护数据库的具体代码示例•探讨主要的PHP应用领域•基于PHP的AJAX技术的具体应用解析•PHP限制上传文件大小的具体解决办法PHP批量上传图片的代码如下:复制代码 代码如下:<html><head><title>uploadpicturemoreonce</title></head><body><formaction=""method="post"enctype="multipart/form-data"><>Pictures:<br/><inputtype="file"name="pictures[]"/><br/><inputtype="file"name="pictures[]"/><br/><inputtype="file"name="pictures[]"/><br/><inputtype="submit"name="upload"value="Send"/></></form></body></html><?phpif($_POST['upload']=='Send'){$dest_folder="picture/";18.if(!file_exists($dest_folder)){19.mkdir($dest_folder);}foreach($_FILES["pictures"]["error"]as$key=>$error){if($error==UPLOAD_ERR_OK){$tmp_name=$_FILES["pictures"]["tmp_name"][$key];$name=$_FILES["pictures"]["name"][$key];$uploadfile=$dest_folder.$name;26.move_uploaded_file($tmp_name,$uploadfile);}}}?>以上代码就是PHP批量上传图片的全部编程,希望对有需要的同学有所帮助。

如果 Web 应用程序中的一个特性需要超过 1 秒或 2 秒才能完成,那么应该怎么办?需要某种离线处理解决方案。学习几种对 PHP 应用程序中长时间运行的作业进行离线服务的方法。 大型的连锁店有一个大问题。每天,在每家商店会发生数千次交易。公司执行官希望对这些数据进行挖掘。哪些产品卖得好?哪些不好?有机产品在哪里卖得好?冰淇淋的销售情况怎么样?  为了捕捉这些数据,组织必须将所有事务性数据装载进一个数据模型,以便更适合生成公司所需的报告类型。但是,这很花费时间,而且随着连锁规模的增长,处理一天的数据可能要花费一天以上的时间。因此,这是个大问题。 现在,您的 Web 应用程序可能不需要处理这么多数据,但是任何站点的处理时间都有可能超过客户愿意等待的时间。一般来说,客户愿意等待的时间是 200 毫秒,如果超过这个时间,客户就会觉得过程 “缓慢”。这个数字基于桌面应用程序,而 Web 使我们更有耐心了。但无论如何,不应该让客户等待的时间超过几秒。所以,要采用一些策略来处理 PHP 中的批处理作业。 分散的方式与 cron 在 UNIX® 机器上,执行批处理的核心程序是 cron 守护进程。这个守护进程读取一个配置文件,这个文件会告诉它要运行哪些命令行以及运行的频率。然后,这个守护进程就按照配置执行它们。在遇到错误时,它甚至能够向指定的电子邮件地址发送错误输出,从而帮助对问题进行调试。 我知道一些工程师强烈主张使用线程技术。“线程!线程才是进行后台处理的真正方法。cron 守护进程太过时了。”  我不这么认为。 这两种方法我都用过,我认为 cron 具备 “Keep It Simple, Stupid(KISS,简单就是美)” 原则的优点。它使后台处理保持简单。不需要编写一直运行的多线程的作业处理应用程序(因此不会有内存泄漏),而是由 cron 启动一个简单的批处理脚本。这个脚本判断是否有作业要处理,执行作业,然后退出。不需要担心内存泄漏。也不需要担心线程停止或陷入无限循环。 那么,cron 是如何工作的?这依赖于您所处的系统环境。我只讨论老式简单的 cron 的 UNIX 命令行版本,您可以向系统管理员咨询如何在自己的 Web 应用程序中实现它。 下面是一个简单的 cron 配置,它在每天晚上 11 点运行一个 PHP 脚本: 0 23 * * * jack /usr/bin/php /users/home/jack/myscript.php 前 5 个字段定义应该启动脚本的时间。然后是应该用来运行这个脚本的用户名。其余的命令是要执行的命令行。时间字段分别是分、小时、月中的日、月和周中的日。下面是几个示例。 命令:  15 * * * * jack /usr/bin/php /users/home/jack/myscript.php 在每个小时的第 15 分钟运行脚本。  命令: 15,45 * * * * jack /usr/bin/php /users/home/jack/myscript.php 在每个小时的第 15 和第 45 分钟运行脚本。 命令: */1 3-23 * * * jack /usr/bin/php /users/home/jack/myscript.php 在早上 3 点到晚上 11 点之间的每分钟运行脚本。 命令 30 23 * * 6 jack /usr/bin/php /users/home/jack/myscript.php 在每星期六的晚上 11:30 运行脚本(星期六由 6 指定)。 可以看到,组合的数量是无限的。可以根据需要控制运行脚本的时间。还可以指定多个要运行的脚本,这样的话,一些脚本可以每分钟都运行,而其他脚本(比如备份脚本)可以每天只运行一次。 为了指定将报告的错误发送到哪个电子邮件地址,可以使用 MAILTO 指令,如下所示: [email protected] 注意:对于 Microsoft® Windows® 用户,有一个等效的 Scheduled Tasks 系统可以用来定期启动命令行进程(比如 PHP 脚本)。  回页首  批处理体系结构的基础知识 批处理是相当简单的。在大多数情况下,采用两个工作流之一。第一个工作流用于进行报告;脚本每天运行一次,它生成报告并将报告发送给一组用户。第二个工作流是在响应某种请求时创建的批作业。例如,我登录进 Web 应用程序中,并要求它向系统中注册的所有用户发送一个消息,将一个新的特性告诉他们。这个操作必须进行批处理,因为系统中有 10,000 个用户。PHP 要花费一段时间才能完成这样的任务,所以它必须由浏览器之外的一个作业来执行。 在第二个工作流中,Web 应用程序只需将信息放在某个位置,让批处理应用程序共享它。这些信息指定作业的性质(例如,“Send this e-mail to all the people on the system”。)批处理程序运行这个作业,然后删除作业。另一种方法是,处理程序将作业标为已完成。无论用哪种方法,作业都应该识别为已完成,这样就不会再次运行它。 本文的其余部分演示在 Web 应用程序前端和批处理后端之间共享数据的各种方法。  回页首  邮件队列 第一种方法是使用专用的邮件队列系统。在这种模型中,数据库中的一个表包含应该发送给各个用户的电子邮件消息。Web 界面使用 mailouts 类将电子邮件添加到队列中。电子邮件处理程序使用 mailouts 类检索未处理的电子邮件,然后再次使用它从队列中删除未处理的电子邮件。 这个模型首先需要 MySQL 模式。 清单 1. mailout.sql     DROP TABLE IF EXISTS mailouts;CREATE TABLE mailouts (  id MEDIUMINT NOT NULL AUTO_INCREMENT,  from_address TEXT NOT NULL,  to_address TEXT NOT NULL,  subject TEXT NOT NULL,  content TEXT NOT NULL,  PRIMARY KEY ( id )); 这个模式非常简单。每行中有一个 from 和一个 to 地址,以及电子邮件的主题和内容。 对数据库中的 mailouts 表进行处理的是 PHP mailouts 类。 清单 2. mailouts.php     <?phprequire_once('DB.php');class Mailouts{  public static function get_db()  {    $dsn = 'mysql://root:@localhost/mailout';    $db =& DB::Connect( $dsn, array() );    if (PEAR::isError($db)) { die($db->getMessage()); }    return $db;  }  public static function delete( $id )  {    $db = Mailouts::get_db();    $sth = $db->prepare( 'DELETE FROM mailouts WHERE id=?' );    $db->execute( $sth, $id );    return true;  }  public static function add( $from, $to, $subject, $content )  {    $db = Mailouts::get_db();    $sth = $db->prepare( 'INSERT INTO mailouts VALUES (null,?,?,?,?)' );    $db->execute( $sth, array( $from, $to, $subject, $content ) );    return true;  }  public static function get_all()  {    $db = Mailouts::get_db();    $res = $db->query( "SELECT * FROM mailouts" );    $rows = array();    while( $res->fetchInto( $row ) ) { $rows []= $row; }    return $rows;  }}?> 这个脚本包含 Pear::DB 数据库访问类。然后定义 mailouts 类,其中包含三个主要的静态函数:add、delete 和 get_all。add() 方法向队列中添加一个电子邮件,这个方法由前端使用。get_all() 方法从表中返回所有数据。delete() 方法删除一个电子邮件。 您可能会问,我为什么不只在脚本末尾调用 delete_all() 方法。不这么做有两个原因:如果在发送每个消息之后删除它,那么即使脚本在出现问题之后重新运行,消息也不可能发送两次;在批作业的启动和完成之间可能会添加新的消息。 下一步是编写一个简单的测试脚本,这个脚本将一个条目添加到队列中。 清单 3. mailout_test_add.php     <?phprequire 'mailout.php';Mailouts::add( '[email protected]',  '[email protected]',  'Test Subject',  'This is a test of the batch mail sendout' );?> 在这个示例中,我添加一个 mailout,这个消息要发送给某公司的 Molly,其中包括主题 “Test Subject” 和电子邮件主体。可以在命令行上运行这个脚本:php mailout_test_add.php。 为了发送电子邮件,需要另一个脚本,这个脚本作为作业处理程序。 清单 4. mailout_send.php     <?phprequire_once 'mailout.php';function process( $from, $to, $subject, $email ) {  mail( $to, $subject, $email, "From: $from" );}$messages = Mailouts::get_all();foreach( $messages as $msg ) {  process( $msg[1], $msg[2], $msg[3], $msg[4] );  Mailouts::delete( $msg[0] );}?> 这个脚本使用 get_all() 方法检索所有电子邮件消息,然后使用 PHP 的 mail() 方法逐一发送消息。在每次成功发送电子邮件之后,调用 delete() 方法从队列中删除对应的记录。 使用 cron 守护进程定期运行这个脚本。运行这个脚本的频率取决于您的应用程序的需要。 注意:PHP Extension and Application Repository(PEAR)存储库包含一个出色的 邮件队列系统 实现,可以免费下载。  回页首  更通用的方法 专门用来发送电子邮件的解决方案是很不错,但是是否有更通用的方法?我们需要能够发送电子邮件、生成报告或者执行其他耗费时间的处理,而不必在浏览器中等待处理完成。 为此,可以利用一个事实:PHP 是一种解释型语言。可以将 PHP 代码存储在数据库中的队列中,以后再执行它。这需要两个表,见清单 5。 清单 5. generic.sql     DROP TABLE IF EXISTS processing_items;CREATE TABLE processing_items (  id MEDIUMINT NOT NULL AUTO_INCREMENT,  function TEXT NOT NULL,  PRIMARY KEY ( id ));DROP TABLE IF EXISTS processing_args;CREATE TABLE processing_args (  id MEDIUMINT NOT NULL AUTO_INCREMENT,  item_id MEDIUMINT NOT NULL,  key_name TEXT NOT NULL,  value TEXT NOT NULL,  PRIMARY KEY ( id )); 第一个表 processing_items 包含作业处理程序调用的函数。第二个表 processing_args 包含要发送给函数的参数,采用的形式是由键/值对组成的 hash 表。 与 mailouts 表一样,这两个表也由 PHP 类包装,这个类称为 ProcessingItems。 清单 6. generic.php     <?phprequire_once('DB.php');class ProcessingItems{  public static function get_db() { ... }  public static function delete( $id )  {    $db = ProcessingItems::get_db();    $sth = $db->prepare( 'DELETE FROM processing_args WHERE item_id=?' );    $db->execute( $sth, $id );    $sth = $db->prepare( 'DELETE FROM processing_items WHERE id=?' );    $db->execute( $sth, $id );    return true;  }  public static function add( $function, $args )  {    $db = ProcessingItems::get_db();    $sth = $db->prepare( 'INSERT INTO processing_items VALUES (null,?)' );    $db->execute( $sth, array( $function ) );    $res = $db->query( "SELECT last_insert_id()" );    $id = null;    while( $res->fetchInto( $row ) ) { $id = $row[0]; }    foreach( $args as $key => $value )    {        $sth = $db->prepare( 'INSERT INTO processing_args  VALUES (null,?,?,?)' );        $db->execute( $sth, array( $id, $key, $value ) );    }    return true;  }  public static function get_all()  {    $db = ProcessingItems::get_db();    $res = $db->query( "SELECT * FROM processing_items" );    $rows = array();    while( $res->fetchInto( $row ) )    {        $item = array();        $item['id'] = $row[0];        $item['function'] = $row[1];        $item['args'] = array();        $ares = $db->query( "SELECT key_name, value FROM   processing_args WHERE item_id=?", $item['id'] );        while( $ares->fetchInto( $arow ) )            $item['args'][ $arow[0] ] = $arow[1];        $rows []= $item;    }    return $rows;  }}?> 这个类包含三个重要的方法:add()、get_all() 和 delete()。与 mailouts 系统一样,前端使用 add(),处理引擎使用 get_all() 和 delete()。 清单 7 所示的测试脚本将一个条目添加到处理队列中。 清单 7. generic_test_add.php     <?phprequire_once 'generic.php';ProcessingItems::add( 'printvalue', array( 'value' => 'foo' ) );?> 在这个示例中,添加了一个对 printvalue 函数的调用,并将 value 参数设置为 foo。我使用 PHP 命令行解释器运行这个脚本,并将这个方法调用放进队列中。然后使用以下处理脚本运行这个方法。 清单 8. generic_process.php     <?phprequire_once 'generic.php';function printvalue( $args ) {  echo 'Printing: '.$args['value']."\n";}foreach( ProcessingItems::get_all() as $item ) {  call_user_func_array( $item['function'],    array( $item['args'] ) );  ProcessingItems::delete( $item['id'] );}?> 这个脚本非常简单。它获得 get_all() 返回的处理条目,然后使用 call_user_func_array(一个 PHP 内部函数)用给定的参数动态地调用这个方法。在这个示例中,调用本地的 printvalue 函数。 为了演示这种功能,我们看看在命令行上发生了什么: % php generic_test_add.php % php generic_process.php Printing: foo% 输出并不多,但是您能够看出要点。通过这种机制,可以将任何 PHP 函数的处理推迟。 现在,如果您不喜欢将 PHP 函数名和参数放进数据库中,那么另一种方法是在 PHP 代码中建立数据库中的 “处理作业类型” 名称和实际 PHP 处理函数之间的映射。按照这种方式,如果以后决定修改 PHP 后端,那么只要 “处理作业类型” 字符串匹配,系统就仍然可以工作。  回页首  放弃数据库 最后,我演示另一种稍有不同的解决方案,它使用一个目录中的文件来存储批作业,而不是使用数据库。在这里提供这个思路并不是建议您 “采用这种方式,而不使用数据库”,这只是一种可供选择的方式,是否采用它由您决定。 显然,这个解决方案中没有模式,因为我们不使用数据库。所以先编写一个类,它包含与前面示例中相似的 add()、get_all() 和 delete() 方法。 清单 9. batch_by_file.php     <?phpdefine( 'BATCH_DIRECTORY', 'batch_items/' );class BatchFiles{  public static function delete( $id )  {    unlink( $id );    return true;  }  public static function add( $function, $args )  {    $path = '';    while( true )    {        $path = BATCH_DIRECTORY.time();        if ( file_exists( $path ) == false )            break;    }    $fh = fopen( $path, "w" );    fprintf( $fh, $function."\n" );    foreach( $args as $k => $v )    {        fprintf( $fh, $k.":".$v."\n" );    }    fclose( $fh );    return true;  }  public static function get_all()  {    $rows = array();    if (is_dir(BATCH_DIRECTORY)) {        if ($dh = opendir(BATCH_DIRECTORY)) {            while (($file = readdir($dh)) !== false) {                $path = BATCH_DIRECTORY.$file;                if ( is_dir( $path ) == false )                {                    $item = array();                    $item['id'] = $path;                    $fh = fopen( $path, 'r' );                    if ( $fh )                    {                        $item['function'] = trim(fgets( $fh ));                        $item['args'] = array();                        while( ( $line = fgets( $fh ) ) != null )                        {                            $args = split( ':', trim($line) );                            $item['args'][$args[0]] = $args[1];                        }                        $rows []= $item;                        fclose( $fh );                    }                }            }            closedir($dh);        }    }    return $rows;  }}?> BatchFiles 类有三个主要方法:add()、get_all() 和 delete()。这个类不访问数据库,而是读写 batch_items 目录中的文件。 使用以下测试代码添加新的批处理条目。 清单 10. batch_by_file_test_add.php     <?phprequire_once 'batch_by_file.php';BatchFiles::add( "printvalue", array( 'value' => 'foo' ) );?> 有一点需要注意:除了类名(BatchFiles)之外,实际上没有任何迹象能够说明作业是如何存储的。所以,以后很容易将它改为数据库风格的存储方式,而不需要修改接口。 最后是处理程序的代码。 清单 11. batch_by_file_processor.php     <?phprequire_once 'batch_by_file.php';function printvalue( $args ) {  echo 'Printing: '.$args['value']."\n";}foreach( BatchFiles::get_all() as $item ) {  call_user_func_array( $item['function'], array( $item['args'] ) );  BatchFiles::delete( $item['id'] );}?> 这段代码几乎与数据库版本完全相同,只是修改了文件名和类名。  回页首  结束语 正如前面提到的,服务器对线程提供了许多支持,可以进行后台批处理。在某些情况下,使用辅助线程处理小作业肯定比较容易。但是,也可以使用传统工具(cron、MySQL、标准的面向对象的 PHP 和 Pear::DB)在 PHP 应用程序中创建批作业,这很容易实现、部署和维护。 参考资料  学习 您可以参阅本文在 developerWorks 全球站点上的 英文原文 。 阅读 IBM developerWorks 的 PHP 项目资源中心,进一步了解 PHP。 PHP.net 是面向 PHP 开发人员的优秀资源。 PEAR Mail_Queue 包 是一个健壮的邮件队列实现,其中包括数据库后端。 crontab 手册 提供了 cron 配置的细节,但是不容易理解。 PHP 手册中关于 Using PHP from the command line 的一节可以帮助您了解如何从 cron 运行脚本。 随时关注 developerWorks 技术事件和 webcast。 了解世界各地即将进行的会议、展览、网络广播和其他 活动,IBM 开放源码开发人员可以通过这些活动了解最新的技术发展。 访问 developerWorks 开源技术专区,获得广泛的 how-to 信息、工具和项目更新,可以帮助您利用开放源码技术进行开发并将其与 IBM 产品结合使用。 developerWorks podcasts 中包括很多适合于软件开发人员的有趣的访谈和讨论。 获得产品和技术 查阅 PEAR -- PHP Extension and Application Repository,其中包含 Pear::DB。 使用 IBM 试用软件 改进您的下一个开放源码开发项目,这些软件可以下载或者通过 DVD 获得。 讨论 developerWorks PHP Developer Forum 为所有 PHP 开发人员提供了讨论技术问题的场所。如果您有关于 PHP 脚本、函数、语法、变量、调试和其他主题的问题,可以在这里提出。 通过参与 developerWorks blog 加入 developerWorks 社区。  关于作者   Jack D. Herrington 是一名高级软件工程师,具有 20 多年的工作经验。他撰写过三本书: Code Generation in Action 、 Podcasting Hacks 和 PHP Hacks,还撰写了 30 多篇文章。

分类:腾博会官方网

时间:2016-02-21 15:08:05