PHP5面向对象

PHP从PHP3开始采用面向对象。在PHP5版本,随着向Zend2引擎转移,对功能进行了大幅度的改善。
采用面向对象开发程序,可以提高程序代码的安全性和可再使用性。从使用PHP5开始尝试引入面向对象
开发/设计怎么样?这篇文章将主要说明与面向对象相关的主要变化。


1 开始
用PHP开发时,以页面为中心编写代码时,总是容易将处理过程写的冗长繁琐。程序的规模稍微大一
点的话,立刻会因安全性方面的困难而令人苦恼。比如说在B页面和A页面进行同样的处理,因为不能把处
理编写成可以重复使用的形式,所以不得不进行拷贝粘贴等工作。这种情况增多的话,一旦拷贝的代码被
改变,需要改动的地方就增多,漏改的可能性也增大。
采用面向对象开发程序的话,就会编出安全性较高的代码。PHP从PHP3开始采用面向对象。在PHP4进行
了一些扩展,到了PHP5则完全重写。这些改进,引入了很多Java和C++中的优良功能,使PHP的面向对象开
发更加正规。这篇文章将主要说明PHP5(Zend Engine 2)在面向对象方面新追加的功能。
让我们以此为契机,尝试一下面相对性开发吧。
2 新功能一览
Zend公布的正式文件中列出的新功能。

支持Private和Protected
抽象方法和抽象类
接口
final关键字
Object的复制
新构造函数
destructor(处理无用的对象)?
常数
例外处理
方法的返回值因对象的不同而不同
静态方法
instanceof 运算符
静态方法的变量操作
当方法的参数是reference时可以为参数设默认值?
类定义的自动读入
访问方法和属性时的操作可以被替换?

下面对他们进行详细介绍。

3 支持private,protected成员
可以将类的属性和方法定义为private或protected。

private 只能从该类内访问的成员
protected 只能从该类和该类的父类内访问的成员
public 从任何类和PHP文件都能访问的成员。

<?
// ------------------------------------------------------------------
class ParentClass {
private $secret = "private变量";
protected $domestic = "protected变量";

function test() {
print "1 : " . $this->secret . "\n";
print "2 : " . $this->domestic . "\n";
}
}
// ------------------------------------------------------------------
class ChildClass extends ParentClass {
function test2() {
// print "3 : " . $this->secret . "\n"; // 不能访问
print "4 : " . $this->domestic . "\n";
}
}
// ------------------------------------------------------------------
$p = new ParentClass();
$c = new ChildClass();

$p->test();

$c->test();
$c->test2();

// print "5 : " . $p->secret . "\n"; // 不能访问
// print "6 : " . $p->domestic . "\n"; // 不能访问
// print "7 : " . $c->secret . "\n"; // 不能访问
// print "8 : " . $c->domestic . "\n"; // 不能访问
// ------------------------------------------------------------------
?>

运行结果

1 : private变量
2 : protected变量
1 : private变量
2 : protected变量
4 : protected变量

如果违反了访问权限的话就会出现Fatal Error错误。

3 抽象方法和抽象类,接口
在PHP中也可以使用抽象方法和抽象类,抽象类是因含有没有方法体的方法而不能实例化的类。没有方
法体的方法是抽象方法。
定义抽象类时使用abstract修饰符

<?
abstract class AbstractClass {
abstract public function test();
}

class Impl1 extends AbstractClass {
public function test() {
print "this is a test by Impl1.\n";
}
}

class Impl2 extends AbstractClass {
public function test() {
print "this is a test by Impl2.\n";
}

// 可以追加新的方法
public function hoge() {
print "hogehoge;\n";
}
}

// $a = new AbstractClass(); // 抽象类不能实例化

$i1 = new Impl1();
$i1->test();

$i2 = new Impl2();
$i2->test();
?>

运行结果

this is a test by Impl1.
this is a test by Impl2.

如上,在抽象方法中无方法体。还有,抽象类不能实例化。如果想实例化,需要开发该抽象类的子类,
此时,子类必须写出抽象类中抽象方法的方法体。(如例中的test方法)
另外,当类中的方法全部为抽象方法时,可以使用接口。

<?
interface MyInterface {
public function test();
}

class Impl implements MyInterface {
public function test() {
print "hogehoge\n";
}
}

$i = new Impl();
$i->test();
?>

运行结果

hogehoge

为实现接口要用到关键字implements。定义借口时,里面的方法可以省略关键字abstract。

5 自动读入类
对未定义的类进行实例化时,需要追加将类自动调出的方法。添加需要用到的类时,全部使用include
调用的话浪费资源,有选择性的调用的话又有些麻烦,此时使用此功能。
将__autoload()方法定义为全局函数,通过该方法可将未用include调用的类实例化。参数为类名。

function __autoload($className) {
include_once $className . ".php";
}

只需通过对以上全局函数(不是方法)的定义,include定义就变得毫无必要(此例是在类名与文件名
相对应的情况下)。实际上上述函数定义最好在所有的页面进行。

*类名中含有大写字母的话,必须转成小写字母。因此上例的类的文件名必须全部用小写字母。

6
定义__set(),__get()方法后,对所有的属性进行访问时处理将发生变化。定义__set()方法后,更新
属性值时,将调用__set()方法。定义__get()方法后,提取属性值时,将调用__get()方法。
__get()方法的参数是属性名,__set()方法的参数是属性名和更新的值。

<?
class PropertyOverload {
public $valList = Array();

function __get($valName) {
print ":: Getter called ($valName).\n";
if( isset($this->valList[$valName]) ) {
// 返回值是原值的1.25倍
return $this->valList[$valName] * 1.25;
} else {
return null;
}
}

function __set($valName, $newValue) {
print ":: Setter called ($valName, $newValue).\n";
$this->valList[$valName] = $newValue;
}

function showStatus() {
print_r( $this->valList );
}
}

$obj = new PropertyOverload();

print "---------------------------------------\n";
$obj->val1 = 100;
print "---------------------------------------\n";
$obj->val2 = 150;
print "---------------------------------------\n";
print $obj->val1 . "\n"; // 调用__get(),返回值是原值的1.25倍
print "---------------------------------------\n";
$obj->showStatus();

?>

运行结果

---------------------------------------
:: Setter called (val1, 100).
---------------------------------------
:: Setter called (val2, 150).
---------------------------------------
:: Getter called (val1).
125
---------------------------------------
Array
(
[val1] => 100
[val2] => 150
)

*只有对没有被作为成员登录的变量(改变量没有被明确定义)访问时,才调用__get(),__set()方法
。不知是有意为之,还是错误。
还有,定义__call()后,调用一个类中未定义的方法时,调用__call()方法。__call()方法的参数是
被调用的方法名和参数数组。

<?
class MethodOverload {
function __call($methodName, $argsArray ) {

print ":: \"$methodName\" Method was called.\n";

switch($methodName) {
case "nomethod":
// 将参数数组中的值指定到已定义的方法的参数中?
call_user_func_array( Array( &$this, "hoge"), $argsArray );
break;
}

}

function hoge($p1, $p2, $p3) {
print "this is test method. Params are ($p1, $p2, $p3).\n";
}
}

$obj = new MethodOverload();
$obj->nomethod(2, 4, 8);

// 调用已定义的方法时,不调用__call()方法
print "----------------------------------------------\n";
$obj->hoge(1, 2, 3);

运行结果

:: "nomethod" Method was called.
this is test method. Params are (2, 4, 8).
----------------------------------------------
this is test method. Params are (1, 2, 3).

?>

使用__set(), __get(), __call()会导致程序安全性降低,一般不鼓励使用。

7 总结
private和protected的引入使对象的信息隐藏成为可能。另外抽象类的实现使PHP可以在更加正规的面
向对象的开发中使用。

你可能感兴趣的:(C++,c,PHP,C#,Zend)