Mais conteúdo relacionado Semelhante a Php More (20) Php More2. PHPMORE VOL 5
本期目录
新闻 2
PHP5 面向对象程序设计之:THIS , SELF 和 PARENT 3
PHP5 面向对象程序设计之: STATIC 和 CONST 7
PEAR 探奇系列之 PEAR::TEXT_PASSWORD 9
PEAR::PEAR 的析构器模拟 16
SMARTY 中 SECTION 的简单使用 18
XMLHTTP 试用手记 23
推荐图书 26
Editors:
Avenger Binzy Cozo Easy Freeman Happay KnightE RainX Shenkong
Thanks to:
.
感谢所有关心和支持 PHPMORE 的人,“感谢你们让我们梦想”。
PHPMORE VOL5
3. 新闻
Zend 和 IBM 合作推出 Zend Core for IBM
PHP 5.0.4 and 4.3.11 Released
PHPMORE.com 改版,推出中文 PHP Blog 聚合服务和 PHP 知识书签服务。欢迎大家到 club.phpe.net 的
PHPMORE 版推荐自己喜爱的 PHP Blog 信息源。
PHPe.net 的论坛已经完成了和 PHP 知识书签的整合,点击帖子中的 图标可以直接将帖子收藏到你的
PHP 知识书签中。
PHPMORE VOL5 2/26
4. PHP5 面向对象程序设计之:this , self 和 parent
文/ heiyeluren
PHP5 是一具备了大部分面向对象语言的特性的语言,比 PHP4 有了很多的面向对象的特性,但是有部分概念也比较
绕人,所以今天拿出来说说,说的不好,请高手见谅. (阅读本文,需要了解 PHP5 的面向对象的知识)
首先我们来明白上面三个关键字: this,self,parent,从字面上比较好理解,是指这,自己,父亲,呵呵,比较好玩
了,我们先建立几个概念,这三个关键字分别是用在什么地方呢?我们初步解释一下,this 是指向当前对象的指针
(我们姑且用 C 里面的指针来看吧),self 是指向当前类的指针,parent 是指向父类的指针。我们这里频繁使用指
针来描述,是因为没有更好的语言来表达,呵呵,语文没学好。 -_-#
这么说还不能很了解,那我们就根据实际的例子结合来讲讲。
(1)this
<? Code ?>
1 <?php
2
3 class UserName
4{
5 //定义属性
6 private $name;
7
8 //定义构造函数
9 function __construct( $name )
10 {
11 $this->name = $name; //这里已经使用了 this 指针
12 }
13
14 //析构函数
15 function __destruct(){}
16
17 //打印用户名成员函数
18 function printName()
19 {
20 print( $this->name ); //又使用了 this 指针
21 }
22 }
23
24 //实例化对象
25 $nameObject = new UserName( "heiyeluren" );
PHPMORE VOL5 3/26
5. 26
27 //执行打印
28 $nameObject->printName(); //输出: heiyeluren
29
30 //第二次实例化对象
31 $nameObject2 = new UserName( "PHP5" );
32
33 //执行打印
34 $nameObject2->printName(); //输出:PHP5
35 ?>
我们看,上面的类分别在 11 行和 20 行使用了 this 指针,那么当时 this 是指向谁呢?其实 this 是在实例化的
时候来确定指向谁,比如第一次实例化对象的时候(25 行),那么当时 this 就是指向$nameObject 对象,那么执
行 18 行的打印的时候就把 print( $this-><name )变成了 print( $nameObject->name ),那么当然就输
出了"heiyeluren"。第二个实例的时候,print( $this->name )变成了 print( $nameObject2->name ),
于是就输出了"PHP5"。所以说,this 就是指向当前对象实例的指针,不指向任何其他对象或类。
(2)self
首先我们要明确一点,self 是指向类本身,也就是 self 是不指向任何已经实例化的对象,一般 self 使用来指向
类中的静态变量。
<? Code ?>
1 <?php
2
3 class Counter
4{
5 //定义属性,包括一个静态变量
6 private static $firstCount = 0;
7 private $lastCount;
8
9 //构造函数
10 function __construct()
11 {
12 $this->lastCount = ++self::$firstCount; //使用 self 来调用静态变量,使
用 self 调用必须使用::(域运算符号)
13 }
14
15 //打印最次数值
16 function printLastCount()
17 {
18 print( $this->lastCount );
19 }
20 }
PHPMORE VOL5 4/26
6. 21
22 //实例化对象
23 $countObject = new Counter();
24
25 $countObject->printLastCount(); //输出 1
26
27 ?>
我们这里只要注意两个地方,第 6 行和第 12 行。我们在第二行定义了一个静态变量$firstCount,并且初始值为
0,那么在 12 行的时候调用了这个值得,使用的是 self 来调用,并且中间使用"::"来连接,就是我们所谓的域运
算符,那么这时候我们调用的就是类自己定义的静态变量$frestCount,我们的静态变量与下面对象的实例无关,
它只是跟类有关,那么我调用类本身的的,那么我们就无法使用 this 来引用,可以使用 self 来引用,因为 self
是指向类本身,与任何对象实例无关。换句话说,假如我们的类里面静态的成员,我们也必须使用 self 来调用。
(3)parent
我们知道 parent 是指向父类的指针,一般我们使用 parent 来调用父类的构造函数。
<? Code ?>
1 <?php
2
3 //基类
4 class Animal
5{
6 //基类的属性
7 public $name; //名字
8
9 //基类的构造函数
10 public function __construct( $name )
11 {
12 $this->name = $name;
13 }
14 }
15
16 //派生类
17 class Person extends Animal //Person 类继承了 Animal 类
18 {
19 public $personSex; //性别
20 public $personAge; //年龄
21
22 //继承类的构造函数
23 function __construct( $personSex, $personAge )
24 {
25 parent::__construct( "heiyeluren" ); //使用 parent 调用了父类的
构造函数
PHPMORE VOL5 5/26
7. 26 $this->personSex = $personSex;
27 $this->personAge = $personAge;
28 }
29
30 function printPerson()
31 {
32 print( $this->name. " is " .$this->personSex. ",this year
" .$this->personAge );
33 }
34 }
35
36 //实例化 Person 对象
37 $personObject = new Person( "male", "21");
38
39 //执行打印
40 $personObject->printPerson(); //输出:
41
42 ?>
我们注意这么几个细节:成员属性都是 public 的,特别是父类的,是为了供继承类通过 this 来访问。我们注意
关键的地方,第 25 行:parent::__construct( "heiyeluren" ),这时候我们就使用 parent 来调用父类的
构造函数进行对父类的初始化,因为父类的成员都是 public 的,于是我们就能够在继承类中直接使用 this 来调
用。
总结:
this 是指向对象实例的一个指针,self 是对类本身的一个引用,parent 是对父类的引用。
PHPMORE VOL5 6/26
8. PHP5 面向对象程序设计之: static 和 const
文/ heiyeluren
PHP5 中加入了很多面向对象的思想,PHP5 的面向对象比较接近 Java 的面向对象思想。我们这里对 PHP5 中的
static 和 const 关键字作用进行一下描述,希望对学习 PHP5 的朋友有帮助。
(1) static
static 关键字在类中是,描述一个成员是静态的,static 能够限制外部的访问,因为 static 后的成员是属于
类的,是不属于任何对象实例,其他类是无法访问的,只对类的实例共享,能一定程序对该成员尽心保护。类的静
态变量,非常类似全局变量,能够被所有类的实例共享,类的静态方法也是一样的,类似于全局函数。类的静态方
法能访问类的静态的属性。另外说明的是,static 的成员,必须使用 self 来访问,使用 this 会出错。
另外,还有一个比较重要的特点就是,如果一个方法使用了 static,那么这个方法就能够在不需要实例化对象的前
提下直接使用该方法.
(关于 this 和 self 的异同,请参考:
http://blog.csdn.net/heiyeshuwu/archive/2004/11/03/165828.aspx )
(2)const
const 是一个定义常量的关键字,类似于 C 中的#define,能够定义一个常量,如果在程序中改变了它的值,那么
会出现错误。
举例说明上面的代码:(注:以下代码来自 phpe.net)
<? Code ?>
<?php
class Counter
{
private static $count = 0;//定义一个静态属性
const VERSION = 2.0;//定义一个常量
//构造函数
function __construct()
{
self::$count++;
}
//析构函数
function __destruct()
{
self::$count--;
PHPMORE VOL5 7/26
9. }
//定义一个静态的方法
static function getCount()
{
return self::$count;
}
}
//创建一个实例
$c = new Counter();
//执行打印
print( Counter::getCount(). "<br>n" ); //使用直接输入类名来访问静态方
法 Counter::getCount
//打印类的版本
print( "Version useed: " .Counter::VERSION. "<br>n" );
?>
嗯,基本到这里了,心里知道的那点东西就讲清楚了,不过我觉得自己对 static 还有点不理解,等以后慢慢去思
考。
作者信息:
heiyeluren
Email: heiyeluren@163.com
Blog: http://blog.csdn.net/heiyeshuwu
PHPMORE VOL5 8/26
10. PEAR 探奇系列之 PEAR::Text_Password
Haohappy/文
上期在介绍 PEAR::Quick_Form 后,收到一些读者来信,希望继续介绍 PEAR 库中的其
它类库。Haohappy 在此作个尝试,在《PHP&More》上开个专栏,今后每一期介绍一个
实用的 PEAR 类,希望大家喜欢。 PEAR 库中目前共有 273 个 package,是全球 PHP 程
序员智慧的结晶,均经过较严格的质量控制,基本上每个 package 都很不错。我选择的原
则主要是两点:1。实用;2。稳定,只选择开发状态为 stable 的版本。如果大家对某个
package 特别感兴趣可以告诉我,将在杂志上优先介绍。
事实上将来有一些 package 是 Haohappy 也没有在实际开发中使用过的,所以写这
一系列文章的过程将是作者和读者共同学习, 共同进步的过程, 希望能得到更多同仁的反馈
和鼓励。有任何意见和建议请到超越 PHP 论坛(club.phpe.net)上的《PHP & MORE》杂
志专区提出,或发信至 haohappy@msn.com,我一定会及时回复。
In reality, it is not lazy to want to be able to do things quickly and easily, especially if
they’re things that need to be done often。聪明的人总是懂得利用资源,不会尝试任何工作
都亲自从头做一遍。如果你也和我一样想站在前人的肩膀之上,就跟我来吧。
关于随机密码
系统自动生成随机密码或口令,这是 WEB 程序常见的功能之一。例如这样的注册模式你一定不会感到陌生:当用户
注册时,系统为用户生成一个随机密码并发至其注册邮箱。用户登录自己的邮箱得到系统所给的随机密码后,再登
录系统修改为自己想要的密码。这和直接发送密码到用户邮箱相比,避免了用户密码在网络上的明文传输,大大增
强了系统安全性。随机密码还常用于“忘记密码”功能,用户忘记密码后,系统可以为之自动再生成一个密码。
/*随机字符串的生成还有一个很酷的应用就是验证码,PEAR 中有一个对应的类库 Text_CAPTCHA。目前
Text_CAPTCHA 还只是 Alpha 版本,所以我们暂不讨论,等到 Stable 版本释出后我会向大家介绍。
Text_CAPTCHA
就基于即将介绍的 Text_Password 开发的。本文中也将会有一个图形验证码的实例,采用 Text_Password+GD
开发。*/
我们在 WEB 开发中生成的密码都是由数字,字母和特殊字符组成的。根据不同的组合方式,密码的类型可以大概分
成纯数字型,纯字母型,纯特殊字符型,数字字母混合型,数字字母特殊字符混合型等。
PEAR::Text_Password 简介
http://pear.php.net/package/Text_Password
今 天 向 大 家 介 绍 的 PEAR 类 是 PEAR::Text_Password , 可 以 称 之 为 随 机 密 码 生 成 器 。
PEAR::Text_Password 是个比较简单的类,只包含一个 PHP 文件(Password.php),代码连注释在内只有 500
多行。Text_Password 易学易用,功能却相当强大,可以满足 WEB 应用中绝大部份情况下的需求(如果你觉得还
需要定制一些自己的功能,可以将这个类库再开发,相当方便)。
Text_Password 的主要特性如下:
可创建多种格式的随机密码,如纯字母,纯数字,纯特殊字符及混用型密码;
PHPMORE VOL5 9/26
11. 可自定义密码的长度(字符数);
可限定密码中只能出现某些字符;
可一次性创建多个密码;
创建基于某个字符串的密码(非随机,使用不同算法对字符串进行处理,如翻转)。
Text_Password 把密码分为 pronounceable(可发音的)和 Unpronounceable(不可发音的)两种类型。
可发音型即纯英文字母型,虽然整个口令不是正常的英文单词,但一般可以划分出音节来发音,有助于记忆,例如
“steagionea”。不可发音型则是混用型,无法发音,如“miC106AIB7” 。显然,可发音型容易记忆而安全性相
对较差, 不可发音型不易记忆但安全性较好。 通常情况下我们不太需要记忆随机密码, 所以选用 Unpronounceable
的情况较常见一些。你可以视实际情况选择。
系统需求:
PHP4.3.* /PHP5
PEAR::Text_Password
使用 Text_Password,实际上我们使用到的只有四个类方法,通过传递不同的参数来生成所需的密码。四个类方
法分别是 create(),createMultiple(),createFromLogin(),createMultipleFromLogin()。下面我们
来举例说明它们的用法。
(1) 创建可发音密码
<? Code - PronounceablePWD.php?>
<?php
require_once "Text/Password.php";
echo "创建 10 个字符的可发音密码....:<BR> ";
echo Text_Password::create(10,'Pronounceable') . "<P>";
echo "创建三个 10 字符的可发音密码...:<BR> ";
print_r(Text_Password::createMultiple(3));
?>
运行结果如图:
在 这 个 程 序 中 , 我 们 使 用 create() 来 创 建 一 个 长 度 为 10 , 类 型 为 pronounceable 的 密 码 ; 使 用
createMultiple()来同时创建三个长度为 10,类型为 pronounceable 的密码密码。
PHPMORE VOL5 10/26
12. (2) 创建不可发音密码
<? Code - UnpronounceablePWD.php?>
<?php
require_once "Text/Password.php";
echo "创建一个 10 字符的不可发音密码....:<BR>";
echo Text_Password::create(10, 'unpronounceable') . "<P>";
echo "创建一个 8 字符且只包含有 a,b,c 的不可发音密码....:<BR>";
echo Text_Password::create(8, 'unpronounceable', 'a,b,c') .
"<P>";
echo "<BR>同时创建 4 个不可发音密码...:n<BR>";
print_r(Text_Password::createMultiple(4, 10,
'unpronounceable'));
echo "<P>";
echo "创建一个长度为 8 的只含有数字的不可发音密码:<BR>";
echo Text_Password::create(8, 'unpronounceable', 'numeric') .
"<P>";
echo "创建一个长度为 8 的只包含数字或字母的不可发音密码::<BR>";
echo Text_Password::create(8, 'unpronounceable',
'alphanumeric') . "<P>";
?>
运行结果如图:
PHPMORE VOL5 11/26
13. 在这个程序中,我们仍然使用的是 create()和 createMultiple()两个类方法,但是在传递参数时使用的是
unpronounceable。
好,看过以上两个例子后,你应该大概知道如何使用 create()和 createMultiple()两个类方法了。create()
有三个参数,分别是密码长度,密码类型和密码组成。
具体用法请参看源代码:
http://cvs.php.net/co.php/pear/Text_Password/Password.php?r=1.12
(2) 创建基于某个字符串的密码
有时候我们希望得到的密码不完全随机,而是有一定规律的。我们希望根据我们所给的字符来获得最终的密码。这
样有个好处就是可以将密码还原成明文,只要我们知道算法。
Text_Password 内建了一些算法来对字符串进行处理。有以下几种算法(或可称操作)
:
• xor
• rotx
• rotx++
• rotx--
• ascii_rotx
• ascii_rotx++
• ascii_rotx--
• shuffle
• reverse
<? Code - GivenStrPWD.php ?>
<?php
require_once "Text/Password.php";
echo "n 密码原文为: 'haohappy', 加密方法为: 'reverse',<BR>加密结果为:
";
echo Text_Password::createFromLogin('haohappy', 'reverse') . "<P>";
echo "n 密码原文为 'haohappy', 加密方法为: 'rot13',<BR>加密结果为:";
echo Text_Password::createFromLogin('haohappy', 'rot13') . "<P>";
echo "n 密码原文为 'haohappy', 加密方法为: 'rotx',<BR>加密结果为:";
echo Text_Password::createFromLogin('haohappy', 'rotx', 13) . "<P>";
echo "n 密码原文为 'haohappy', 加密方法为: 'rotx++',<BR>加密结果为:";
echo Text_Password::createFromLogin('haohappy', 'rotx++', 13) . "<P>";
echo "n 密码原文为 'haohappy', 加密方法为: 'rotx--',<BR>加密结果为:";
echo Text_Password::createFromLogin('haohappy', 'rotx--', 13) . "<P>";
PHPMORE VOL5 12/26
14. echo "n 密码原文为 'haohappy', 加密方法为: 'xor',<BR>加密结果为:";
echo Text_Password::createFromLogin('haohappy', 'xor', 5) . "<P>";
echo "n 密码原文为 'haohappy', 加密方法为: 'ascii_rotx',<BR>加密结果为:
";
echo Text_Password::createFromLogin('haohappy', 'ascii_rotx', 5) . "<P>";
echo "n 密码原文为 'haohappy', 加密方法为: 'ascii_rotx++',<BR>加密结果为:
";
echo Text_Password::createFromLogin('haohappy', 'ascii_rotx++', 5) . "<P>";
echo "n 密码原文为 'haohappy', 加密方法为: 'ascii_rotx--',<BR>加密结果为:
";
echo Text_Password::createFromLogin('haohappy', 'ascii_rotx--', 5) . "<P>";
echo "n 密码原文为 'haohappy', 加密方法为: 'shuffle',<BR>加密结果为:";
echo Text_Password::createFromLogin('haohappy', 'shuffle', 1) . "<P>";
echo "n<b>密码组</b>原文为: 'haohappy', 'martin', 'vanhoucke', 'jansen', 加密
方法为: 'reverse':n";
$logins = array('haohappy', 'martin', 'vanhoucke', 'jansen');
echo "结果如下:<pre>";
print_r(Text_Password::createMultipleFromLogin($logins, 'reverse'));
echo "</pre>";
?>
运行结果如图:
你可以按 F5 刷新几次,会发现除了 Shuffle 操作(打乱)之外,其它结果都是固定不变,也即非随机的。
PHPMORE VOL5 13/26
15. 以上即 Text_Password 的三个主要应用,相信你已经初步掌握。
应用实例――图形验证码:
下面 Haohappy 将给出一个应用实例,那就是大家都非常熟悉的图形验证码。虽然只是一个简单的例子,却是一个
完整的验证码程序的核心部份。思路是采用随机的背景图,再用不同的颜色写上随机字符串。
首先,我们准备三个图形背景文件,分别命名为 bg1.png,bg2.png,bg3.png,放在 images 目录下。
代码如下:
<? Code - ImageCode.php?>
<?php
require_once "Text/Password.php";
$string = Text_Password::create(10, 'pronounceable');
$num = rand(1,3);
header("Content-type: image/png");
$im = imagecreatefrompng("images/bg$num.png");
switch ($num) {
case 1:
$orange = imagecolorallocate($im, 253, 238, 227); //字体颜色
break;
case 2:
$orange = imagecolorallocate($im, 255, 204, 51);
break;
case 3:
$orange = imagecolorallocate($im, 255,255,200);
break;
}
$px = (imagesx($im) - 7.5 * strlen($string)) / 2; //位置
imagestring($im, 5, $px-3, 2, $string, $orange); //写上随机字符串
imagepng($im);
imagedestroy($im);
?>
PHPMORE VOL5 14/26
16. 运行结果如下:
左图为随机码类型 pronounceable,右图为 unpronounceable
使用 Text_Password 的好处就在这里,可以非常方便地使用你想要的随机码类型。
程序非常简单,只有二十多行,但功能算是相当强大,想使用程序进行边缘识别不那么容易,安全性较高。
至少比腾讯网站上 QQ 免费注册的那个验证码强多了:) 当然你也可以再加入随机杂点,画线,使用随机字体,旋
转等等(如果有必要的话) 。你可以在网页中加入<IMAGE SRC='imagetest2.php'>来引用该验证码,配合
Session,就可以在用户登录时进行图形验证码认证。具体不详述,没什么难度。
如果对几个图像函数不熟悉,请自行查阅 PHP 手册。
参考资料:
End-user Documentation and API documentation of PEAR::Text_Password
PHPMORE VOL5 15/26
17. PEAR::PEAR 的析构器模拟
EasyChen / 文
Pear 是 Pear 的基类,其中提供了 Pear 类的一些基本服务,主要包括
o 析构器的模拟
o 错误处理机制
这里我们说析构器的模拟 。虽然 PHP4 中的 class 是没有析构器的,但是所有扩展自 Pear 的 class,都会在程序
结束时调用_classname()函数来析构。很神奇是吧,我们就来看看 pear 是怎么做到的。
首先,我们需要在构造器中调用$this->Pear()方法,实际上运行的是如下代码:
<? Code ?>
$classname = get_class($this);
if ($this->_debug) {
print "PEAR constructor called, class=$classnamen";
}
if ($error_class !== null) { $this->_error_class = $error_class;
}
while ($classname) { $destructor = "_$classname";
if (method_exists($this, $destructor)) {
global $_PEAR_destructor_object_list;
$_PEAR_destructor_object_list[] = &$this;
break;
} else { $classname = get_parent_class($classname);
}
}
可以看到,Pear 取得了当前对象的 class 名,然后开始拼接出析构器的名称_classname,接着调用 method_exists
方法察看当前对象是否存在着方法,如果存在,把这个对以引用方式推入一个数组。从这个数组的名字上我们就可
以知道,析构时 pear 将遍历这个数组中的对象并调用其析构方法。
需要注意的是,这里为什么会使用一个数组。实际上,pear 用 while 语句制造了一个类似递归的效果。当当前对象
没有析构器时,pear 会去找它的父类的析构器,直到找到为止。
现在剩下的就是一个问题了,如何在程序执行完时触发这个析构过程?
要明白这一点,需要先了解一个函数 register_shutdown_function。这个函数可以添加一个函数,使 php 在脚本
运行结束前,调用它。可以注册多个函数,调用的顺序和注册的顺序一致。
pear 的代码里边有这么一句。
PHPMORE VOL5 16/26
18. register_shutdown_function("_PEAR_call_destructors");
显然,_PEAR_call_destructors 就是那个析构过程了,代码和 Pear()有些类似。
<? Code ?>
function _PEAR_call_destructors()
{
global $_PEAR_destructor_object_list;
if (is_array($_PEAR_destructor_object_list) &&
sizeof($_PEAR_destructor_object_list))
{ reset($_PEAR_destructor_object_list);
while (list($k, $objref) = each($_PEAR_destructor_object_list))
{ $classname = get_class($objref);
while ($classname) { $destructor = "_$classname";
if (method_exists($objref, $destructor)) { $objref->$destructor();
break;
} else { $classname = get_parent_class($classname);
}
}
} // Empty the object list to ensure that destructors are
// not called more than once. $_PEAR_destructor_object_list = array();
} // Now call the shutdown functions if
(is_array($GLOBALS['_PEAR_shutdown_funcs'])
AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value)
{ call_user_func_array($value[0], $value[1]);
}
}
}
总结一下,Pear 在初始化时建立了需要析构的对象数组,并利用了 register_shutdown_function 触发析构函数,
_PEAR_call_destructors,从而完美的模拟了析构过程。
PHPMORE VOL5 17/26
19. Smarty 中 section 的简单使用
翟翔/文
什么是 section?
就像在 Smarty 官方手册里提到的,模板 section 是用来循环数组里的数据的。所有的 section 标签必须和
/section 标签成对儿使用。必须使用的参数是 name 和 loop。section 的 name 可以随你所好,可以是由字母、
数字和下划线组成的。section 可以嵌套使用,互相嵌套的 section 它们的 name 必须与众不同。变量 loop(通
常是数组的值)决定着 section 将要循环的次数。当用 section 显示一个变量时,section 的 name 必须紧跟
在变量名的后面,并用中括号 [] 括起来。当 loop 变量没有值时,sectionelse 就会运行。
下面就是一个 name 为 left_block,loop 为$LEFT_BLOCK_BODY 的 section,注意到<div
class=”left_block”></div>当中显示变量的方法了么?section 的 name 也就是 left_block 紧跟在
$LEFT_BLOCK_BODY 的后面,并用中括号 [] 括起来了。
<{section name=left_block loop=$LEFT_BLOCK_BODY}>
<div class="left_block"><{$LEFT_BLOCK_BODY[left_block]}></div>
<{/section}>
为什么要使用 section?
就像 phpBB2 的成员列表,如下图,显示的内容
当你设计成员列表时(如图 1 所示)
,你要用到 section。
(图 1)
因为你无法确认有多少个用户注册,即使确认就 100 个限制用户注册,用传统的 table 设计网页你需要作的是牲
口般的工作,所以把这些交给 section 来处理吧。
其实还有很多地方可以用到 section。比如用 div 来作网页布局的时候,左、中、右区域的区块儿和模块儿都是
由后台数据库的 block management 来管理的,网页设计者根本就不知这些动态浮动的区块儿、模块儿在什么地
方、什么时候、什么样式、什么内容出现,或者这些区块儿和模块儿压根儿就不让你看见(管理员控制面板对一般
用户就是隐藏的),section 可以轻松地管理登陆框、导航栏、新闻发布、谁在线、语言选择等区块儿和模块儿。
如何使用 section?
PHPMORE VOL5 18/26
20. Smarty 中的 section 和 PHPLib 中 template 的 block 很相似, section 更为 smart。
但 如果你使用过 PHPLib
的 block 很快你就会过渡到 section,如果你以前压根儿就没有听说过这些事儿, 反而更容易掌握 section 的
概念,因为什么都不知道嘛。Just kidding^_^
来个简单的导航栏元素设计的例子。传统的导航栏设计很实诚(如图 2 所示),
(图 2)
有多少个链接就用 dreamweaver 设计几个,有千千万万个怎么办呢?而且还要随时变化怎么办呢?你只用设计一
个链接其他的就让 section 去循环显示好了。 dreamweaver 设计一个名为 navigation.htm 的页面
用 (只保留
了 table 当中要用到的元素,其余的 html 元素在不影响显示的前提下均以省略)
,如下面 html 代码。
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td><h2><{$L_TITLE_NAVIGATION}></h2></td>
</tr>
<{section name=navigation loop=$l_navigation}>
<tr>
<td><img src="<{$IMG_DOT}>" width="12" height="12">
<a
href="<{$u_navigation[navigation]}>"><{$l_navigation[navigation]}></a></td>
</tr>
<{/section}>
</table>
其中<a href="<{$u_navigation[navigation]}>"></a>就定义了超链接变量,
<{$l_navigation[navigation]}>就定义了超链接的名称,用<{section name=navigation
loop=$l_navigation}>和<{/section}>框住要循环显示的部分,一个自动化的导航栏的表现层就设计好了。
(请参看 MVC 模型)
光有皮肤没有骨架是支撑不起导航栏来的,所以让我们看看如何用 PHP 代码控制显示导航栏的。写一个名为
navigation.php 的 PHP 文件,代码如下:
PHPMORE VOL5 19/26
21. $template->assign("l_navigation", array(
//要在其他地方给$lang[' …… ']负值
$lang['index'],
$lang['your_account'],
$lang['downloads'],
$lang['submit_news'],
$lang['topics'],
$lang['top10']
)
);
$template->assign("u_navigation",array(
"./index.php",
"./modules.php?name=Your_Account",
"./modules.php?name=Downloads",
"./modules.php?name=Submint_News",
"./modules.php?name=Topics",
"./modules.php?name=Top10"
)
);
你肯定要惊叹:“really?”真的是这么简单呀^_^
首先,$template->assign 是在调用 Smarty 的 smarty 类当中的 assign 函数,assign 的意思就是赋值、分
配、指派的意思。$template->assign 给 navigation.htm 网页模板中的 l_navigation 变量赋了一个数组,
并提供了 6 个变量型的数组值(你要在其他地方给它们负值,或者直接像给超链接地址负值一样用" …… "的形式)
——用来显示超链接的名称,其中的数组键值用 PHP 默认的 0、1、2……就省略了;还给 u_navigation 变量赋了一
个数组,相对称的也是 6 个但已给出数值的变量——用来定义超链接的去向(其中运用了参数?name 来判断转向哪个
模块儿)。你可能会产生疑问:循环的次数在哪里定义的?loop 变量名仅仅是$l_navigation 数组呀!如果你有
机会查看 Smarty 的代码,你会发现 loop = count($l_navigation),只是这个过程被封装了,你只用调用这
个 section 接口就 OK 了。
然后,利用 smarty 类当中的 display 函数,就可以运行 navigation.php 查看你的导航栏了
PHPMORE VOL5 20/26
22. $template->display(“navigation.htm”);
进一步使用 section
就像我前面提到的,section 主要在处理多个重复其不断变化的元素上优势明显。这里由于篇幅有限,就把思想和
大家共享,把未完善的内容留给以后的文章。变化的数据来源于数据库,那么在$template->assign 一个 section
变量的时候可以用到 DB(是 PEAR 提供的对多种数据库操作的集成度很高的类,可以一次编写标准的 SQL 语句在大
多数主流数据库上到处运行)和 section 的综合利用。
在网页中显示居于左侧的区块儿和模块儿
$sql = "SELECT block_value FROM sirtoozee_blocks
WHERE block_side = 'left' and block_visble = 'true'
ORDER BY 'weight ";
//用 getCol 这个 API 可以得到一维数组$block = array('','',...)
$block_value = $db->getCol($sql);
$template->assign("LEFT_BLOCK_BODY", $block_value)
你可以 print_r($block_value)看看$block_value 这个数组结构是不是就是 array('' …… '', ... )的
结构一模一样。其中具体的 DB 类的使用和网页 layout 布局我会在以后的文章中详细讲解。
如果大家对调用 Smarty 不熟悉,我在这里也简单介绍安装配置 Smarty 的方法:
到 http://smarty.php.net 下载 stable 版本的 smarty,将压缩包里./libs 文件夹里的所有文件解压缩到
Smarty(需要自己新建)文件夹中,并将你设计的网页模板文件,如 navigation.htm 放在 templates(需要
自己新建)文件夹下,还需要为 Smarty 新建 config、cache、templates_c 文件夹用来编译生成临时文件,
最后形成如下的文件目录结构:
./
./Smarty/internals
./Smarty/plugins
./Smarty/Config_File.class
./Smarty/debug
./Smarty/Smarty.class
./Smarty/Smarty_Compiler.class
./templates
PHPMORE VOL5 21/26
23. ./templates_c
./config
./cache
用如下代码调用 Smarty 类
//
//模板引擎配置,采用 smarty-2.6.6
//
include("./Smarty/Smarty.class.php");
$template = new Smarty;
//安装并配置 Smarty 模板引擎
$template->template_dir = "./templates/ ";
$template->compile_dir = "./templates_c";
$template->config_dir = "./configs";
$template->cache_dir = "./cache";
//为了和 javascript 标签区别开来
$template->left_delimiter = "<{";
$template->right_delimiter = "}>";
您可以通过如下方式和作者翟翔联系
Email:legendren2008@yahoo.com.cn
PHPMORE VOL5 22/26
24. XmlHttp 试用手记
EasyChen / 文
什么是 XmlHttp
Xmlhttp 是一种浏览器对象,可用于模拟 http 的 GET 和 POST 请求。配合 JavaScript 可以实现页面数据在无
刷新下的定时数据更新,如果应用在聊天室、文字直播上可以取得较好的视觉效果。
IE 中的 XmlHttp 对象
在 IE 中 XmlHttp 被实现为 ActiveX 对象,通常使用
var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
来创建一个对象,然后使用该对象的 open 方法来发出一个 Http 请求。
xmlhttp.open("GET", fragment_url);
这时候浏览器已经发出了 Http 请求,我们需要注册一个匿名函数给 XmlHttp 对象的 onreadystatechange 方
法,这样当请求返回时,xmlhttp 就会自动调用我们注册的这个函数,下边是一个实际的例子。
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
element.innerHTML = xmlhttp.responseText;
}
}
因为我们不需要再发送任何信息,所以用下边的语句结束
xmlhttp.send(null);
我们将上边的过程封装为一个函数,下边是这个函数的完整代码:
function loadFragmentInToElement(fragment_url, element_id)
{
var element = document.getElementById(element_id);
var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
xmlhttp.open("GET", fragment_url);
PHPMORE VOL5 23/26
25. xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
element.innerHTML = xmlhttp.responseText;
}
}
xmlhttp.send(null);
}
函数的调用方法如下所示:
loadFragmentInToElement( 'http://domain.com/url.php' , DynamicContent_id );
有了上边的代码,再配合 JavaScript 的定时函数,我们就可以实现定时的无刷新数据更新了,下边这个函数每隔
5 秒对 element_id 的数据进行一次更新。
function refresh( element_id )
{
loadFragmentInToElement( 'show.php' , '' + element_id );
setTimeout( "refresh('ts')" , 5000 );
}
在 IE 上使用 XmlHttp 要注意的问题
特别要注意的是由于 IE 的 Cache 的关系,我们看见的 XmlHttp 并不总是最新读取的那一个,为了让 IE 不启用
Cache,我们发送给 IE 一个特殊的 Header,用 PHP 实现如下:
header( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" );
header( "Last-Modified: " . gmdate( "D, d M Y H:i:s" ) . "GMT" );
header( "Cache-Control: no-cache, must-revalidate" );
header( "Pragma: no-cache" );
XmlHttp 对象在 Gecko 上的实现
Gecko 上的 XmlHttp 和 IE 上略有不同,它并不需要通过 ActiveX 来创建。另外回调函数必须在 open 方法之前
注册,而 IE 并不要求,这是一个很需要注意的问题。
使用 JavaScript 实现 XmlHttp 的跨浏览器应用
为了能在多种浏览器上有一个统一的实现,我们可以用 JavaScript 来对不同浏览器的差异进行封装。这里我们采
用 Andrew Gregory 的实现。首先我们要引用 Andrew Gregory 的一个名为 xmlhttprequest.js 的 Js 脚本。
PHPMORE VOL5 24/26
26. <script type="text/javascript" src="xmlhttprequest.js"></script>
然后在创建 XmlHttp 对象时统一使用 new XMLHttpRequest()就可以了;其它的方法不用改变。这个 Js 脚本允
许 我 们 在 IE 、 Gecko ( Mozilla/FireFox ) 和 Opera 的 特 定 版 本 使 用 XmlHttp 。 下 边 是 调 整 后 的
loadFragmentInToElement 函数,这个函数在 IE6 和 FireFox1.0pre 上运行通过。
<script type="text/javascript" src="xmlhttprequest.js"></script>
<script>
function loadFragmentInToElement(fragment_url, element_id)
{
var element = document.getElementById(element_id);
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
element.innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("GET", fragment_url);
xmlhttp.send(null);
}
</script>
xmlhttprequest.js 文件和具体的使用例子可以在我写的一个 DEMO 中找到。
XmlHttp 中的中文乱码问题
在默认情况下, XmlHttp 都是使用 Utf-8 字符集, 而我们使用的多是 GB2312 字符集, 这就要求我们进行 GB2312
到 Utf-8 的转码。PHP 提供了一个可选的专码模块,可以实现多种字符集之间的相互转化。加载这个专码模块的方
法如下:
打开 PHP 配置文件 php.ini,将 ;extension=php_mbstring.dll(*nix 是 php_mbstring.so) 前的分
号去掉。重新启动 Apache 以后,这个模块就可以使用了。如果有错误出现,请检查扩展目录的路径设置是否正确。
加载这个模块以后,我们就可以使用 mb_convert_encoding 函数来转码了:
$utf8_string = mb_convert_encoding( $gb_string , 'UTF-8' , 'GB2312' );
将转码后的字符输出就可以看见正确显示的中文了。
PHPMORE VOL5 25/26
27. 推荐图书
著名的 J2ee 核心模式,最近原书第 李维的新作,对于面向对象的初学者 《程序员修炼之道》同系列的书,深
二版的中文版出来了,书不错,翻译 和 Delphi For dotnet 的用户来说很不 入浅出的讲解了 JUNIT 的使用。
得也不错。 错,Delphi 也开始 UT 和 TDD 了
PHPMORE VOL5 26/26