2010年2月26日星期五

9个PHP库简介和下载

1. ReCAPTCHA
The reCAPTCHA 库让你可以为网站创建高级的 CAPTCHA 系统,这个系统其实是用来生成验证信息的,甚至包括语音验证。当然还有 reCAPTCHA 服务可以使用,其提供易用的免费 API,值得在你的网站试试。

下载 ReCAPTCHA | 获得 API Key | 文档

2. Akismet
Akismet 是个供小站点使用的免费服务,用来修改规范将加入数据库的评论(防止恶意评论)。这个库一直在改善。

详细参考 Akismet 介绍

3. Services_JSON
JSON 是人类能容易理解的信息传递格式。不过如果你并未使用 5.2.0 以后版本的 PHP(从那以后 PHP 有了 JSON 官方支持),那么就应该试试这个库。

查看 Services_JSON

4. Smarty
Smarty就是鼎鼎大名的官方模版库了。它提供了不少有用的功能。其实使用 PHP 的人都该瞧瞧。

下载 Smarty | 官方文档

5. pChart
pChart 是极其有名的数据图形库。它能为数据展示提供各种美丽的图表。其实使用 PHP 的人都一定会碰到使用它的情况。

下载 pChart | 文档| 查看演示

6. SimplePie
SimplePie 让你轻松提取内容(好比 RSS feeds)。它能和多种语言交互,也能处理各种格式的 feed。

下载 SimplePie | 查看文档 | 为独特的 RSS Feeds 拓展 SimplePie

7. XML-RPC PHP Library
有时你需要使用 XML-RPC 技术去和其他网站交互,那么试试这个 XML-RPC PHP 库吧。

下载 XML-RPC PHP | 查看文档

8. Amazon S3
Amazon 有名的云计算平台叫做 “S3″。这里就有Amazon S3 库 让你不用任何附加工具就可以使用云,上传大量数据文件。

下载 Amazon S3 PHP Class

9. PHPMailer
大多数 web 应用都在使用 PHP 的 mail() 函数。PHPMailer 让你更加灵活地处理 Email 的发出,不但支持任何格式,还可以加入附件并自定义 header。

下载 PHPMailer | 查看文档

2010年2月23日星期二

PHP 单件模式

当需要一个特殊类的唯一实例时,使用这个名字叫单件的模式。基于单件模式的类能实例化和初始化这个类的一个实例,并且提供每时每刻绝对相同的连接。一般情况下使用名为getInstance()的静态方法实现。

PHP4 单件模式
在DbConn的构造函数中,你可能对$fromGetInstance的默认参数感到疑惑。在对象被直接实例化时,它能够提供(很微弱的)保护:除非这个默认值变成e (在PHP的数学常量中 M_E = 2.718281828459),否则这段代码会报错。
[php title="PHP4"]
class DbConn {
function DbConn($fromGetInstance=false) {
if (M_E != $fromGetInstance) {
trigger_error('The DbConn class is a Singleton,' .' please do not instantiate directly.');
}

}

function &getInstance() {
$key = '__some_unique_key_for_the_DbConn_instance__';
if (!(array_key_exists($key, $GLOBALS) && is_object($GLOBALS[$key]) && 'dbconn' == get_class($GLOBALS[$key]) )) {
$GLOBALS[$key] =& new DbConn(M_E);
}
return $GLOBALS[$key];
}

}
[/php]
如果不选用这个“神秘参数”-类型保护,建立一个全局标记是另外一个选择,用它来验证是通过getInstance()方法来创建的对象。保护方式从“知道它的名字”改变成“它存在于环境中”。

下面例子解释了为什么构造函数保护代码有一个全局的标识:
[php]
class DbConn {
function DbConn() {
$token = '__some_DbConn_instance_create_semaphore__';
if (!array_key_exists($token, $GLOBALS)) {
trigger_error('The DbConn class is a Singleton,' .' please do not instantiate directly.');
}
}

function &getInstance() {
static $instance = array();
if (!$instance) {
$token = '__some_DbConn_instance_create_semaphore__';
$GLOBALS[$token] = true;
$instance[0] =& new DbConn;
unset($GLOBALS[$token]);
}

return $instance[0];
}
}
[/php]

PHP4允许改变构造函数中$this的值。在过去,会习惯 $this = null;当有一个创建构造错误时,确保无效的对象不能被代码继续使用。但这种技术在PHP5中并不兼容。

另外,杀昂上段代码中另外一个重点是引用操作&的用法。有两种地方需要使用&。第一种是在函数定义时,在函数名字前用来表示将返回一个引用。第二种是将新的DbConn对象赋值给$GLOBALS数组。
getInstance()方法的条件检查,常常被写成没有警示的情况下运行,甚至在E_ALL的错误级别下也不会提示。它检查在$GLOBAL数组中适当的位置是否有一个DbConn对象,如果没有,就在那里创建这个对象。这个对象能被重复创建或者这个对象在之前已经被这个方法创建过。当方法结束时,可以确认已经拥有这个类的有效实例,而且它已经被有效初始化。

[php title="PHP5 单件模式"]
class DbConn {
static $instance = false;

private function __construct() {}

public function getInstance() {
if (!DbConn::$instance) {
DbConn::$instance = new DbConn;
}
return DbConn::$instance;
}
}
[/php]
组合使用静态方法和静态变量保持这个实例,并且设置构造函数为私有,例化类而创建实例,这个类就不能被直接实例化。

[php title="Monostate Pattern(单态模式):类单件模式"]
class ApplicationConfig {
var $_state;

function ApplicationConfig() {
$key = '__stealth_singleton_state_index__';
if (!(array_key_exists($key, $GLOBALS) && is_array($GLOBALS[$key]))) {
$GLOBALS[$key] = array();
}

$this->_state =& $GLOBALS[$key];
}

function set($key, $val) {
$this->_state[$key] = $val;
}

function get($key) {
if (array_key_exists($key, $this->_state)) {
return $this->_state[$key];
}
}
}
[/php]
在PHP中,通过把一个全局变量绑定到一个实例变量来实现MonoState。
这个技巧的核心是$this->state =& $GLOBALS[$key]; 。在确定$GLOBALS[$key]是一个数组后,代码绑定一个全局数组的引用给类变量$this->state。从而,任何$this->state的改变都自然而言地同步到全局数组,包括类的其它实例。

这个技巧能够在任何PHP的自动全局(superglobal)数组使用,尤其在用户消息队列$_SESSION中有很显著的效果。MonoState能通过你的代码为用户存储一系列的使用信息(要显示的信息可能是从另外一个页面传入的)。

资料:

PHP工厂模式

重构-引入叁数对象
方法中如果有很多参数,常常变得很复杂,而且容易导致错误。可以引入一个封装参数的对象来替代一大堆的参数。举例来说,"start date" and "end date" 叁数可以用一个 DateRange 对象一起代替。

一个基类就是不能被直接实例化的类。 一个基础的类包含一个或更多的基础方法,这些方法必须在子类被覆盖。一旦所有的抽象方法被覆盖了, 子类也就产生了。
基类为许多相似的类创造了好的原型。

迟加载(Lazy Loading)的工厂, 使用工厂的另一个好处就是它具有迟加载的能力。这种情况常被用在:一个工厂中包括很多子类,这些子类被定义在单独的PHP文件内。
迟加载——在迟加载模式中是不预加载所有的操作(像包含PHP文件或者执行数据库查询语句),除非脚本中声明要加载。

实现迟加载的页面工厂(page factory)的代码可以写作:
[php]
class PageFactory {
function &getPage() {
$page = (array_key_exists('page', $_REQUEST)) ? strtolower($_REQUEST['page']): '';

switch ($page) {
case 'entry': $pageclass = 'Detail'; break;
case 'edit': $pageclass = 'Edit'; break;
case 'comment': $pageclass = 'Comment'; break;
default: $pageclass = 'Index';
}

if (!class_exists($pageclass)) {
require_once 'pages/' . $pageclass.'.php';
}

return new $pageclass;
}
}
[/php]
工厂模式, 它是一种代码中建立新对象的管理技术。可以把复杂对象的建立集中起来,甚至用不同的类代替不同的对象。最后,工厂模式支持OOP技术中的多态也是很重要的。

2010年2月22日星期一

PHP值对象模式

[php]
class BadDollar {
protected $amount;

public function __construct($amount=0) {
$this->amount = (float)$amount;
}

public function getAmount() {
return $this->amount;
}

public function add($dollar) {
$this->amount += $dollar->getAmount();
}
}

class Work {
protected $salary;

public function __construct() {
$this->salary = new BadDollar(200);
}

public function payDay() {
return $this->salary;
}

}

class Person {
public $wallet;
}

require_once 'simpletest/unit_tester.php';

require_once 'simpletest/reporter.php';

// the test

class TestingTestCase extends UnitTestCase {

function testBadDollarWorking() {
$job = new Work;
$p1 = new Person;
$p2 = new Person;
$p1->wallet = $job->payDay();
$this->assertEqual(200, $p1->wallet->getAmount());
$p2->wallet = $job->payDay();
$this->assertEqual(200, $p2->wallet->getAmount());
$p1->wallet->add($job->payDay());
$this->assertEqual(400, $p1->wallet->getAmount());
//this is bad — actually 400
$this->assertEqual(200, $p2->wallet->getAmount());
//this is really bad — actually 400
$this->assertEqual(200, $job->payDay()->getAmount());

}
}
$test = new TestingTestCase('Testing Unit Test');

$test->run(new HtmlReporter());
[/php]

这是书上的例题。说实在话,开始我并没有搞清楚问题出在那~。
书上解说p1和p2用的是同一个BadDollar的对象实例。按照以往的思维,对于这句话是难于理解的,p1和p2都是新创建的对象,而不是如p2=p1这样赋值,它们怎么会使用同样的对象呢?当然,如果记得PHP5对象赋值的原理,肯定就不难理解了。因为PHP5的对象赋值的处理方式,所以$job::salary,$p1::wallet和$p2::wallet这三个看上去不同的对象实例虽然使用着不同的“标识符”,但实际上,它们全都指定到了同一个对象实例。

另外,执行Value Object时,php4和php5是有区别的。PHP4操作所有的对象都遵循Value Objects对象规律的——它的赋值操作相当于对对象做了一个拷贝。

[php]
class Dollar {
protected $amount;

public function __construct($amount=0) {
$this->amount = (float)$amount;
}

public function getAmount() {
return $this->amount;
}

public function add($dollar) {
return new Dollar($this->amount + $dollar->getAmount());
}
}
[/php]
PHP5里用值对象设计模式时,需要注意以下几个方面:

  • 保护值对象的属性,禁止被直接访问。

  • 在构造函数中就对属性进行赋值。

  • 去掉任何一个会改变属性值的方式函数,否则属性值很容易被改变。



PHP4中使用对象去模仿PHP5中的对象句柄时的三个规则:

  • 通过指针 $obj =& new class; 来创建对象。

  • 用指针 function funct(&$obj) param{} 来传递对象。

  • 用指针 function &some_funct() {} $returned_obj =& some_funct() 来获取一个对象。

PHP5 的对象赋值机制

[php]
class SimpleClass{
public $var = 'a default value';

public function displayVar() {
echo $this->var;
}
}
$instance = new SimpleClass();

$assigned = $instance;
$reference =& $instance;

$instance->var = '$assigned will have this value';

$instance = null; // $instance and $reference become null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
[/php]

看到PHP设计模式中值对象模式中的例题,对于结果总感到有点疑惑。回头看了下PHP5的对象赋值才真正清楚。

php5 改写了OOP底层。当类生成一个实例(对象)的时候,返回值$instance并不是对象本身,而只是对象的一个id(或者资源句柄),所以,当$instance被赋值给$assigned的时候,$assigned也指向了这个对象,这有点像普通变量的引用(&)操作。所以,当对$instance初始化的时候,$assigned也被初始化了。但是,当$instance被销毁(=null)的时候,因为对应的对象还有一个句柄存在($assigned),所以对象并不会被销毁,析构函数也不会被触发。结果,var_dump($assigned)是对象的值,而$instance已经是空句柄,显示null。$reference因为与$instance有类似普通变量间的引用关系,所以也成为空句柄,显示 null。

2010年2月18日星期四

PHP 编辑器/IDE之路

2007-12 ~ 2008-02
这段时间很忠诚的在用着EditPlus, 没想过要换,也没想过是不是不方便。现在想来,那个时候自己是怎么可以忍受连代码折行功能都没有的编辑器的?

2008-03 ~ 2008-03
领导强制每个人用Eclipse。晕的是,要我先试用,然后用英文写一手册。写完手册,我就把这个弃之一边了~因为占内存能力实在太强了。

2008-03 ~ 2008-08
在SourceForge上发现了NotePad++,很喜欢TA的"Show Indent Guide"功能,另外还有函数提示..反正是这个很对自己那个时候的”胃口“。但好景不长,问题出现了。用这个写的代码传到*nix系统上不能正确执行,总报session开始之前页面有输出的错误。费了好大的功夫才查到,原来用这个编辑器新建的文件在文件开头多了个不可显示的字符~,把文件用十六进制显示时才可看到。出了这样的问题,这个肯定是不能在继续用了~

2008-08 ~ 2008-10
这段时间,试用了很多IDE, VIM,、PHP Designer、PHPEdit, PHP Coder, Dev-PHP etc。 慕名Zend Studio,用了一个多月~后来说是什么到期了,让我又彻底抛弃这个。

2008-10 ~ 2008-11
我想我是对开源和*nix有着无法言喻的好感,如果看到哪个软件Windows 、*nix下都有,不出意外的话,都会要去试试。再加上这段时间看了些Perl, Python, 而Komodo Edit都他们又都支持,让我是不得不试用它了。开始用的几天感觉真的很好,NotePad++下的"Show Indent Guide"又见到了,还是函数提示和跟踪等。但不久发现CPU有点无法负担,不得不忍痛割爱。
因为安装Python,它自带了SciTE编辑器,用它写了python的程序,感觉还可以。

2008-11 ~ 2009-08
这大半年的时间,基本上都是在用NuSphere PHPEd。
中间有段时间因为写Ruby,知道了radrails,后来网上一查,radrails又被aptana给买了。到aptana的官网上看到它支持PHP的编写~遂也试了下,但也不尽如人意。
某天心血来潮,去看了下 PHP MVC 框架 Codeigniter 的视频,发现视频上的IDE视觉上让人很舒服。找了下,好像那是Mac 下的TextMate,没有Windows系列。但网上评价 e 基本上是仿造TextMate的,试用了,后来就把这做为平时修改单个文件的编辑器了。

2009-09 ~ 目前
九月中旬的时候进入一家新的公司。新入公司,许是想看看我的耐心还是什么的,放任了将近一周多的时间让我自己瞎折腾。因为无聊,又把Komodo Edit给down下来装上了。哈,竟然用的非常顺利~
但很不妙的是把它安装在购置的笔记本上,竟是无法运行。用UStudio,出现之前用NotePad++同样的问题~,呵,估计在这台机器上只能是回到NuSphere PHPEd的时代了

常用小工具:取色器、图片压缩、截屏、屏幕尺等

闲坐无聊,在PHPChina上瞎逛,看到一东东,下下了,试了下,感觉不错,最主要是绿色的,免费的~
主要功能:
绿色拾取器
图片压缩工具
屏幕处理工具(截图、屏幕尺、坐标、白板、量角器、放大镜)
下载地址:kits.zip

2010年2月4日星期四

昨天 今天 明天

越来越拒绝外界的一切沟通,就只愿静静的盯着电视或是书本,放任自己的心游走在那些虚构的故事中,跟着TA们一起喜怒哀乐。
不是不明白这样的状态会让我更加无法走出心中的阴影。也曾努力的试着去改变,结果却不尽然~我不知道,到底是我自己使自己尘封,还是心本就已尘封?
找不到可以述说的人。所以,总是在不得已的情况下,口是心非的回答着各式各样的令我不愿面对的问题。

又要过年了,心里却没有丝丝的喜悦,隐隐的担忧着来年家人和自己到底该如何是好。对于TA们,心怀愧疚却无力解决TA们所担心的一切。唯一值得安慰的是:可以回家,见到久未谋面的妈妈和弟弟。

前面在路上遇到一个调查,题目是「在这个城市我还打算停留多长时间,几个月,一年,两年还是更多?」,而我的答案是「不知道」,对方再三跟我确认答案是否是如此后,无奈的摇头放开我,因为我的答案对TA们真无实用价值。河水是朝着大海而流,可如今,对于未来的日子,我却越来越迷茫。回首在这城市的六年,最开始的日子,好像只是一瞬间;而最近几年,却总是让我恍惚~记忆好像一直停在那里,不曾离开。一友人·说,我之所以对最几年无法忘怀,是因为发生了太多的事情。可是,为什么当我回望时,却没有一件是可以具体描述的呢?一切好像都只是我内心的煎熬和挣扎~

日子是这样的在我幽幽转转的心情中溜走,做过的多少决定也总是在转身之后又将TA们抛之脑后。内心是怎样的脆弱的不堪一击,以致始终在众人面前对于某些事情讳莫如深,即使是最好的友人。

妈妈和弟弟的以后是我如今最最担忧的。我是多想通过自己的努力为TA们创造一份属于TA们的宁静,而不至于像现在这样每日每夜的为明天而担忧。但现实是怎样的残酷呢?所有的一切好像总是要自己不停的要求下才会给予一点,对这样的方式,心中有说不出的厌恶!!!或许是我真的太过天真和理想~

CSS Zen Garden

CSS Zen Garden
CSS设计者们休憩领地~

Nginx是越来越盛行了

Nginx是越来越盛行了
豆瓣也加入行列了~

2010年2月2日星期二

可能未曾用过的PHP函数

sys_getloadavg()
sys_getloadavt()可以获得系统负载情况。该函数返回一个包含三个元素的数组,每个元素分别代表系统再过去的1、5和15分钟内的平均负载。

与其让服务器因高负载宕掉,不如在系统负载很高时主动die掉一个脚本,sys_getloadavg()就是用来帮你实现这个功能的。 不过遗憾的是该函数windows下无效。

pack()
pack()能将md5()返回的32位16进制字符串转换为16位的二进制字符串,可以节省存储空间。

cal_days_in_month()
cal_days_in_month()能够返回指定月份共有多少天。

_()
WordPress开发者经常能见到这个函数,还有_e()。这两个函数功能相同,与gettext()函数结合使用,能实现网站的多语言化。具体可参见PHP手册的相关部分介绍。

get_browser()
在发送页面前先看看用户的浏览器都能做些什么是不是挺好?get_browser()能获得用户的浏览器类型,以及浏览器支持的功能,不过首先你需要一个php_browscap.ini文件,用来给函数做参考文件。

要注意,该函数对浏览器功能的判断是基于该类浏览器的一般特性的。例如,如果用户关闭了浏览器对JavaScript的支持,函数无法得知这一点。但是在判断浏览器类型和OS平台方面,该函数还是很准确的。

debug_print_backtrace()
调试用函数,能帮助发现代码中的逻辑错误。要理解这个函数,可看如下例子:
[php]
$a = 0;

function iterate() {
global $a;
if( $a < 10 )
recur();
echo $a . ",";
}

function recur() {
global $a;
$a++;

// how did I get here?
echo "\n\n\n";
debug_print_backtrace();

if( $a < 10 )
iterate();
}

iterate();
[/php]
OUTPUT:
[text]
#0 recur() called at [E:\www\11.php:7]
#1 iterate() called at [E:\www\11.php:23]



#0 recur() called at [E:\www\11.php:7]
#1 iterate() called at [E:\www\11.php:20]
#2 recur() called at [E:\www\11.php:7]
#3 iterate() called at [E:\www\11.php:23]



#0 recur() called at [E:\www\11.php:7]
#1 iterate() called at [E:\www\11.php:20]
#2 recur() called at [E:\www\11.php:7]
#3 iterate() called at [E:\www\11.php:20]
#4 recur() called at [E:\www\11.php:7]
#5 iterate() called at [E:\www\11.php:23]



#0 recur() called at [E:\www\11.php:7]
#1 iterate() called at [E:\www\11.php:20]
#2 recur() called at [E:\www\11.php:7]
#3 iterate() called at [E:\www\11.php:20]
#4 recur() called at [E:\www\11.php:7]
#5 iterate() called at [E:\www\11.php:20]
#6 recur() called at [E:\www\11.php:7]
#7 iterate() called at [E:\www\11.php:23]
......
10,10,10,10,10,10,10,10,10,10,
[/text]

metaphone()
这个函数返回单词的metaphone值,相同读音的单词具有相同的metaphone值,也就是说这个函数可以帮你判断两个单词的读音是否相同。不过对中文无效。。。

natsort()
natsort()能将一个数组以自然排序法进行排列
[php]
$items = array('100 apples', '5 apples', '110 apples', '55 apples');

sort($items);
print_r($items);

echo '<br />';
natsort($items);
print_r($items);
[/php]

OUTPUT:
[text]
Array ( [0] => 100 apples [1] => 110 apples [2] => 5 apples [3] => 55 apples )
Array ( [2] => 5 apples [3] => 55 apples [0] => 100 apples [1] => 110 apples )
[/text]

levenshtein()
Levenshtein() 两个单词之间的“距离”。它可告诉如果想把一个单词变成另一个单词,需要插入、替换和删除多少字母。
[php]
$dictionary = array('php', 'javascript', 'css');

$word = 'testphp';

$best_match = $dictionary[0];
$match_value = levenshtein($dictionary[0], $word);

foreach($dictionary as $w) {
$value = levenshtein($word, $w);
if( $value < $match_value ) {
$best_match = $w;
$match_value = $value;
}
}

echo $best_match ;
[/php]

glob()
glob()会让你感觉用opendir(), readdir()和closedir()来寻找文件非常蠢。
[php]
foreach(glob('*.php') as $file) {
echo $file . "\n";
}
[/php]