2007年8月14日星期二

PHP Unit 安装

1. 安装
方法一:通过 PEAR 安装
pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit

方法二:
1.下载压缩包,解压,设置 include_path
2. 将 pear-phpunit 脚本改名为 phpunit
3. 将脚本中 @php_bin@ 替换为 php 命令行解析器
4. 拷贝到 PATH 能搜索到的目录,或者 在 PATH 添加相应目录。
5. linux下添加执行属性 (chmod +x phpunit)

2007年7月9日星期一

Observer pattern

观察者模式 Observer Pattern


观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单:一个对象通过添加一个方法(该方法允许另一个对象,即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。



SPL 提供的 Observer 接口:
观察者:
SplObserver::update(SplSubject $subject)
观察者接口,由被观察对象调用。

主题(被观察者):
SplSubject::attach(SplObserver $observer)
参数:
$observer 要添加的观察者

SplSubject::detach(SplObserver $observer)
参数:
$observer 要删除的观察者

SplSubject::notify()
通知所有观察者.

2007年6月13日星期三

The Template Method Pattern in PHP 5

php5模板方法模式


节选翻译,原文: http://www.zend.com/zend/php5/php5-OOP.php

什么是模板方法模式?定义一个操作中算法的骨架,将一些步骤的执行放到其子类中.
这是一种重要的代码重用技术。模板方法模式通常用在类库中提取类的共同的行为。
模板方法设计模式可以让子类去重新定义一个操作中的某些步骤,而不用去改变这个操作的结构。
这些可重新定义的步骤可以在基类中标为强制的或者可选的。由于这些步骤都会归于单独的方法,所以子类必须为强制的步骤提供一个实现方法,可选的则可以忽略。

模板方法可以实现一个操作中不变的部分,把那些可能变化的行为留给子类实现。也可以用于仅在在指定点提供hook操作来给子类扩展行为。

例子


Listing 1. AbstractClass.php



Listing 1 显示了一个迷你的模板方法,叫做 templateMethod()。它使用了两个方法:mandatoryOperation() 和 optionalOperation(), 这两个可以在子类中重定义。
abstract class AbstractClass {
public final function templateMethod() {
print "AbstractClass::templateMethod() called.\n";

$this->mandatoryOperation();
$this->optionalOperation();
}

protected abstract function mandatoryOperation();

protected function optionalOperation() {
}
}



Listing 2: ConcreteClass.php



Listing 2 显示了一个和 AbstractClass 类对应的子类。 ConcreteClass 重定义了mandatoryOperation() 和 optionalOperation() 方法。

require_once 'AbstractClass.php';

class ConcreteClass extends AbstractClass {
protected function mandatoryOperation() {
print "ConcreteClass::mandatoryOperation() called.\n";
}

protected function optionalOperation() {
print "ConcreteClass::optionalOperation() called.\n";
}
}


Listing 3: example.php



最后, Listing 3 显示了如何调用 ConcreteClass 。

require_once 'ConcreteClass.php';

$o = new ConcreteClass;
$o->templateMethod();


输出:
AbstractClass::templateMethod() called.
ConcreteClass::mandatoryOperation() called.
ConcreteClass::optionalOperation() called.

2007年6月3日星期日

使用 Zend_Console_Getopt 处理 PHP 命令行

Linux 下写Shell只要在第一行加上
#!/path/to/php
然后将脚本加上执行属性即可 chmod +x

注意:Windows下编程再上传的朋友要注意。换行必须以linux格式,否则脚本会报错

require_once 'Zend/Console/Getopt.php';

定义规则:

使用短语
$opts = new Zend_Console_Getopt('abp:');

使用长语法
$opts = new Zend_Console_Getopt(
array(
'apple|a' => 'This option chooses apple, with no parameter',
'banana|b=i' => 'This option chooses banana, with required integer parameter',
'pear|p-s' => 'This option chooses pear, with optional string parameter'
)
);


捕获异常
try {
$opts = new Zend_Console_Getopt('abp:');
$opts->parse();
} catch (Zend_Console_Getopt_Exception $e) {
echo $e->getUsageMessage();
exit;
}


获取命令行选项和参数
$b = $opts->getOption('b');
$p = $opts->getOption('p');


另一种方法是使用 __get() and __isset() 魔术方法
if (isset($opts->b)) {
echo "I got the b option.\n";
}
$p = $opts->p; // null if not set

2007年4月21日星期六

概念: interface 和 abstract class 的区别

什么是 abstract class
PHP 5 引入抽象类和方法。抽象类不能被实例化。任何类只要包含有抽象方法(即使只有一个抽象方法)就必须也被定义为抽象。定义为抽象的方法只需要简单的声明而不用实现。
从抽象类继承的时候,所有父类中标记为抽象方法的声明都必须在子类中定义;此外,这些方法还必须用相同的(或更弱的)访问控制。比如,如果抽象方法定义为保护(protected),函数实现必须被定义为protected或者public

抽象类例子:
abstract class AbstractClass
{
// Force Extending class to define this method
abstract protected function getValue();
abstract protected function prefixValue($prefix);

// Common method
public function printOut() {
print $this->getValue() . "\n";
}
}

class ConcreteClass1 extends AbstractClass
{
protected function getValue() {
return "ConcreteClass1";
}

public function prefixValue($prefix) {
return "{$prefix}ConcreteClass1";
}
}

class ConcreteClass2 extends AbstractClass
{
public function getValue() {
return "ConcreteClass2";
}

public function prefixValue($prefix) {
return "{$prefix}ConcreteClass2";
}
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";

$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."\n";



什么是 interface
Object Interface 对象接口允许你创建这种代码,一个类必须实现的指定方法,而又不必定义这些方法如何处理。接口使用interface关键字定义,和标准类定义一样,但是任何方法都没有内容。接口内所有的方法声明都必须为公开(public),这是接口的本质(呵呵,所谓接口嘛,就是用于交互的)。
实现
要实现一个接口,使用 implements 操作符。接口中的所有方法都必须在一个类中实现;不这么做会导致一个致命错误(fatal error)。 如果想要的话,使用逗号分隔每个接口,一个类可以实现多个接口。
注意:一个类不能实现两个有同样函数名的接口,因为这导致这个函数的含义模糊。

接口的例子:
// Declare the interface 'iTemplate'
interface iTemplate
{
public function setVariable($name, $var);
public function getHtml($template);
}

// Implement the interface
// This will work
class Template implements iTemplate
{
private $vars = array();

public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}

public function getHtml($template)
{
foreach($this->vars as $name => $value) {
$template = str_replace('{' . $name . '}', $value, $template);
}

return $template;
}
}

// This will not work
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements iTemplate
{
private $vars = array();

public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
}


实现多个接口:
class MyClass implements anInterface, anotherInterface {
//...
}


如果想要继承一个类并实现一个接口,先使用“extends”然后“implements”:
class MyChildClass extends MyParentClass implements MyInterface
{
// definition
}



interface 和 abstract class 的区别
PHP 5 中类没有多重继承,但可以实现多个接口。这应该是接口的主要用途。这点和Java类似,和C++不同。应该是学java,对多重继承的一种解决方式吧。

代码形式上来说,接口只是一个声明,其方法没有任何实现代码;抽象类的方法既可以没有实现代码,也可以拥有实现代码。

2007年4月10日星期二

使用模块设计 Zend Framework 控制器

启动文件:基本上一样,唯一的区别:
//$frontController->setControllerDirectory('./application/controllers');
//将原来的设置控制器目录改成以下方式:
$frontController->setControllerDirectory(array(
'default' => './application/controllers/',
'admin' => './application/controllers/admin/')
);


index.php
<?php
/**
* Bootstrap file
*/
error_reporting(E_ALL|E_STRICT);
date_default_timezone_set('Asia/Shanghai');

set_include_path('.' . PATH_SEPARATOR . '../library/'
. PATH_SEPARATOR . './application/models'
. get_include_path());

require_once "Zend/Loader.php";
// autoload class
spl_autoload_register(array('Zend_Loader', 'autoload'));

// load configuration
$config = new Zend_Config_Ini('./application/config.ini', 'general');
Zend_Registry::set('config', $config);

// setup database
$db = Zend_Db::factory($config->db->adapter, $config->db->config->asArray());

Zend_Db_Table::setDefaultAdapter($db);

// register the view we are going to use
$view = new Zend_View();
$view->setScriptPath('./application/views');
Zend_Registry::set('view', $view);

$auth = Zend_Auth::getInstance();

// setup controller
$baseUrl = substr($_SERVER['PHP_SELF'], 0,
strpos($_SERVER['PHP_SELF'], '/index.php'));
$frontController = Zend_Controller_Front::getInstance();
$frontController->setBaseUrl($baseUrl);
$frontController->throwExceptions(true);

$frontController->setControllerDirectory(array(
'default' => './application/controllers/',
'admin' => './application/controllers/admin/')
);

// run!
$frontController->dispatch();
?>


default模块:
在application/controllers目录下的IndexController.php原来一样设计,不需要改动:
<?php
class IndexController extends Zend_Controller_Action
{
public function init()
{
}

public function indexAction()
{
}

public function otherAction()
{
}
}
?>


admin模块:
在application/controllers/admin目录下的IndexController.php是这样的。注意类名:admin_IndexController, 这符合目录-类名转换的约定。
<?php
class admin_IndexController extends Zend_Controller_Action
{
public function init()
{
}

public function indexAction()
{
}

public function otherAction()
{
}
}
?>


好了,大功告成,就这么多。
访问的时候和原来是一样的。
http://localhost/ 访问默认模块index控制器indexAction() application/controllers/IndexController.php
http://localhost/admin 访问admin模块index控制器indexAction() application/controllers/admin/IndexController.php

2007年3月20日星期二

PHP 安装

PHP 安装
这篇文章为新手准备。
其实详细信息PHP安装文档中都已经详细说明了。

  1. Unix下安装:

    1. gzip -d httpd-2_0_NN.tar.gz
    2. tar xvf httpd-2_0_NN.tar
    3. gunzip php-NN.tar.gz
    4. tar -xvf php-NN.tar
    5. cd httpd-2_0_NN
    6. ./configure --enable-so
    7. make
    8. make install

    现在已经将 Apache 2.0.NN 安装在 /usr/local/apache。本安装支持可装载模块
    和标准的 MPM prefork。之后,可以使用如下命令启动 Apache 服务器:
    /usr/local/apache2/bin/apachectl start
    如果成功,可以停止 Apache 服务器并继续安装 PHP:
    /usr/local/apache2/bin/apachectl stop.

    9. cd ../php4-NN

    10. 现在需要配置 PHP。在这里可以用各种各样的参数来自定义PHP,例如启动哪些
    扩展功能包的支持等。用 ./configure --help 命令可以列出当前可用的所有参
    数。在此例中,将给出一个在有 MySQL 支持的 Apache 2 上进行配置的范例。
    用户本地的 apxs 的路径可能会不同,事实上,在用户的系统中,它可能被命名为
    apxs2。

    ./configure --with-apxs2=/usr/local/apache2/bin/apxs

    11. make
    12. make install

    如果决定在安装后改变配置选项,只需重复最后的三步,然后需要重新启动 Apache
    使新模块生效。无需重新编译。

    请注意,除非明确有提示,否则“make install”命令将安装 PEAR、各种 PHP 工具
    诸如 phpize,安装 PHP CLI 等等。

    13. 配置 php.ini

    cp php.ini-dist /usr/local/lib/php.ini

    可以编辑 php.ini 文件以修改 PHP 的选项。如果想要把此文件放到另外的位置,
    需要在步骤 10 添加 --with-config-file-path=/path 选项。

    如果选择 php.ini -recommended,请务必阅读其中的变更的列表,它们将影响
    PHP 的执行。

    14. 编辑 httpd.conf 文件以调用 PHP 模块。LoadMolude 表达式右边的路径必须指向
    系统中的 PHP。以上的 make install 命令可能已经完成了这些,但务必要检查。

    对于 PHP 4:
    LoadModule php4_module modules/libphp4.so

    对于 PHP 5:
    LoadModule php5_module modules/libphp5.so

    15. 告知 Apache 将特定的扩展名解析成 PHP,例如,让 Apache 将扩展名 .php
    解析成 PHP。可以将任何扩展名指定为 PHP,只需添加它们,每一个用空格分隔。
    例如,要添加 .phtml:

    AddType application/x-httpd-php .php .phtml

    通常还将 .phps 扩展名设置成显示高亮的 PHP 源文件,可以这样来完成:

    AddType application/x-httpd-php-source .phps

    16. 启动 Apache 服务器:
    /usr/local/apache2/bin/apachectl start


  2. Windows下安装:
    将以下两行加入到 Apache 的 httpd.conf 配置文件中设定 Apache 2.0 的 PHP 模块

    # 对 PHP 4 用这两行:
    LoadModule php4_module "c:/php/php4apache2.dll"
    # 别忘了从 sapi 目录中把 php4apache2.dll 拷贝出来!
    AddType application/x-httpd-php .php

    # 对 PHP 5 用这两行:
    LoadModule php5_module "c:/php/php5apache2.dll"
    AddType application/x-httpd-php .php

    # 配置 php.ini 的路径
    PHPIniDir "C:/php"




参考资料:
http://www.php.net/manual/zh/install.php

2007年3月18日星期日

概念: 构造函数和析构函数

构造函数和析构函数
构造函数
void __construct ( [mixed args [, ...]] )

PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。

注: 如果子类中定义了构造函数则不会暗中调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。

例子 19-6. 使用新标准的构造函数
<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}

class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}

$obj = new BaseClass();
$obj = new SubClass();
?>


为了实现向后兼容性,如果 PHP 5 在类中找不到 __construct() 函数,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。因此唯一会产生兼容性问题的情况是:类中已有一个名为 __construct() 的方法,但它却又不是构造函数。
析构函数
void __destruct ( void )

PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。

例子 19-7. 析构函数示例
<?php
class MyDestructableClass {
function __construct() {
print "In constructor\n";
$this->name = "MyDestructableClass";
}

function __destruct() {
print "Destroying " . $this->name . "\n";
}
}

$obj = new MyDestructableClass();
?>


和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()。

注: 析构函数在脚本关闭时调用,此时所有的头信息已经发出。

注: 试图在析构函数中抛出一个异常会导致致命错误。

2007年1月29日星期一