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