helloworld
EOD;
public$var3=1+2;
public$var4=self:
:
myStaticMethod();
public$var5=$myVar;
//正确的属性声明
public$var6=myConstant;
public$var7=array(true,false);
//在php5.3.0及之后,下面的声明也正确
public$var8=<<<'EOD'
helloworld
EOD;
}
?
>
跟heredocs不同,nowdocs能够使用在静态变量,也能使用在静态声明。
Example2示例:
使用nowdoc初始化属性
php
classfoo{
//AsofPHP5.3.0
public$bar=<<<'EOT'
bar
EOT;
}
?
>
三、类常量
我们可以在类中定义常量。
常量的值将始终保持不变。
在定义和使用常量的时候不需要使用$符号。
常量的值必须是一个定值,不能是变量,类属性或其它操作(如函数调用)的结果。
Example1定义和使用一个类常量
php
classMyClass
{
constconstant='constantvalue';
functionshowConstant(){
echoself:
:
constant."\n";
}
}
echoMyClass:
:
constant."\n";
$classname="MyClass";
echo$classname:
:
constant."\n";//PHP5.3.0之后
$class=newMyClass();
$class->showConstant();
echo$class:
:
constant."\n";//PHP5.3.0之后
?
>
Example2静态数据示例
php
classfoo{
//PHP5.3.0之后
constbar=<<<'EOT'
bar
EOT;
}
?
>
和heredocs(字符串边界符)不同,nowdocs可以用在任何静态数据中。
四、自动加载对象
在5.3.0版之前,__autoload函数抛出的异常不能被catch语句块捕获并会导致一个致命错误。
从5.3.0+之后,__autoload函数抛出的异常可以被catch语句块捕获,但需要遵循一个条件。
如果抛出的是一个自定义异常,那么必须存在相应的自定义异常类。
__autoload函数可以递归的自动加载自定义异常类。
Note:
如果使用PHP的CLI交互模式时,Autoloading是无效的。
Example1Autoload例子
php
function__autoload($class_name){
require_once$class_name.'.php';
}
$obj=newMyClass1();
$obj2=newMyClass2();
?
>
五、构造函数和析构函数
1.构造函数
void__construct([mixed、\$args[,\$...]])
PHP5允行开发者在一个类中定义一个方法作为构造函数。
具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
Note:
如果子类中定义了构造函数则不会隐式调用其父类的构造函数。
要执行父类的构造函数,需要在子类的构造函数中调用parent:
:
__construct()。
Example1使用新标准的构造函数
php
classBaseClass{
function__construct(){
print"InBaseClassconstructor\n";
}
}
classSubClassextendsBaseClass{
function__construct(){
parent:
:
__construct();
print"InSubClassconstructor\n";
}
}
$obj=newBaseClass();
$obj=newSubClass();
?
>
为了实现向后兼容性,如果PHP5在类中找不到__construct()函数,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。
因此唯一会产生兼容性问题的情况是:
类中已有一个名为__construct()的方法,但它却又不是构造函数。
2.析构函数
void__destruct(void)PHP5引入了析构函数的概念,这类似于其它面向对象的语言,如C++。
析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
Example3析构函数示例
php
classMyDestructableClass{
function__construct(){
print"Inconstructor\n";
$this->name="MyDestructableClass";
}
function__destruct(){
print"Destroying".$this->name."\n";
}
}
$obj=newMyDestructableClass();
?
>
和构造函数一样,父类的析构函数不会被引擎暗中调用。
要执行父类的析构函数,必须在子类的析构函数体中显式调用parent:
:
__destruct()。
析构函数即使在使用exit()终止脚本运行时也会被调用。
在析构函数中调用exit()将会中止其余关闭操作的运行。
六、访问控制
对属性或方法的访问控制,是通过在前面添加关键字public、protected或private来实现的。
由public所定义的类成员可以在任何地方被访问;由protected所定义的类成员则可以被其所在类的子类和父类访问(当然,该成员所在的类也可以访问);而由private定义的类成员则只能被其所在类访问。
1.对类成员的访问控制
类成员都必须使用关键字public、protected或private进行定义,默认为public
Example1声明类成员
php
/**
*DefineMyClass
*/
classMyClass
{
public$public='Public';
protected$protected='Protected';
private$private='Private';
functionprintHello()
{
echo$this->public;
echo$this->protected;
echo$this->private;
}
}
$obj=newMyClass();
echo$obj->public;//这行能被正常执行
echo$obj->protected;//这行会产生一个致命错误
echo$obj->private;//这行也会产生一个致命错误
$obj->printHello();//输出Public、Protected和Private
/**
*DefineMyClass2
*/
classMyClass2extendsMyClass
{
//可以对public和protected进行重定义,但private而不能
protected$protected='Protected2';
functionprintHello()
{
echo$this->public;
echo$this->protected;
echo$this->private;
}
}
$obj2=newMyClass2();
echo$obj->public;//这行能被正常执行
echo$obj2->private;//未定义private
echo$obj2->protected;//这行会产生一个致命错误
$obj2->printHello();//输出Public、Protected2,但不会输出Private
classBar
{
publicfunctiontest(){
$this->testPrivate();
$this->testPublic();
}
publicfunctiontestPublic(){
echo"Bar:
:
testPublic\n";
}
privatefunctiontestPrivate(){
echo"Bar:
:
testPrivate\n";
}
}
classFooextendsBar
{
publicfunctiontestPublic(){
echo"Foo:
:
testPublic\n";
}
privatefunctiontestPrivate(){
echo"Foo:
:
testPrivate\n";
}
}
$myFoo=newfoo();
$myFoo->test();//Bar:
:
testPrivate
//Foo:
:
testPublic
?
>
Note:
为了兼容性考虑,在PHP4中使用var关键字对变量进行定义的方法在PHP5中仍然有效(只是作为public关键字的一个别名)。
在PHP5.1.3之前的版本,该语法会产生一个E_STRICT警告。
2.对方法的访问控制
类中的方法都必须使用关键字public、protected或private进行定义。
如果没有设置这些关键字,则该方法会被设置成默认的public。
Example2声明类中的方法
php
/**
*DefineMyClass
*/
classMyClass
{
//构造函数必须是public
publicfunction__construct(){}
//声明一个public的方法
publicfunctionMyPublic(){}
//声明一个protected的方法
protectedfunctionMyProtected(){}
//声明一个private的方法
privatefunctionMyPrivate(){}
//这个方法也是public的
functionFoo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}
$myclass=newMyClass;
$myclass->MyPublic();//这行能被正常执行
$myclass->MyProtected();//这行会产生一个致命错误
$myclass->MyPrivate();//这行会产生一个致命错误
$myclass->Foo();//Public、Protected和Private都被调用了
/**
*DefineMyClass2
*/
classMyClass2extendsMyClass
{
//Thisispublic
functionFoo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();//这行会产生一个致命错误
}
}
$myclass2=newMyClass2;
$myclass2->MyPublic();//这行能被正常执行
$myclass2->Foo2();//Public和Protected都被调用了,但Private不会被调用
?
>
七、对象继承
继承已为大家所熟知的一个程序设计特性,PHP的对象模型也使用了继承。
继承将会影响到类与类,对象与对象之间的关系。
比如,当扩展一个类,子类就会继承父类的所有公有和保护方法。
但是子类的方法会覆盖父类的方法。
继承对于功能的设计和抽象是非常有用的,而且对于类似的对象增加新功能就无须重新再写这些公用的功能。
Example1继承代码示例
php
classfoo
{
publicfunctionprintItem($string)
{
echo'Foo:
'.$string.PHP_EOL;
}
publicfunctionprintPHP()
{
echo'PHPisgreat.'.PHP_EOL;
}
}
classbarextendsfoo
{
publicfunctionprintItem($string)
{
echo'Bar:
'.$string.PHP_EOL;
}
}
$foo=newfoo();
$bar=newbar();
$foo->printItem('baz');//Output:
'Foo:
baz'
$foo->printPHP();//Output:
'PHPisgreat'
$bar->printItem('baz');//Output:
'Bar:
baz'
$bar->printPHP();//Output:
'PHPisgreat'
?
>
八、范围解析操作符(:
:
)
范围解析操作符(也可称作PaamayimNekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员、方法和常量,还可以用于覆盖类中的成员和方法。
当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字。
把PaamayimNekudotayim选作该操作符的名字似乎有些奇怪。
然而,这是Zend开发小组在写ZendEngine0.5(被用于PHP3中)时所作出的决定。
事实上这个词在希伯莱文就是双冒号的意思。
Example1在类的外部使用:
:
操作符
php
classMyClass{
constCONST_VALUE='Aconstantvalue';
}
echoMyClass:
:
CONST_VALUE;
?
>
self和parent这两个特殊的关键字是用于在类的内部对成员或方法进行访问的。
Example#2:
:
frominsidetheclassdefinition
php
classOtherClassextendsMyClass
{
publicstatic$my_static='staticvar';
publicstaticfunctiondoubleColon(){
echoparent:
:
CONST_VALUE."\n";
echoself:
:
$my_static."\n";
}
}
OtherClass:
:
doubleColon();
?
>
当一个子类覆盖其父类中的方法时,PHP不会再执行父类中已被覆盖的方法,直到子类中调用这些方法为止。
这种机制也作用于构造函数和析构函数、重载及魔术函数。
Example3调用父类的方法
php
classMyClass
{
protectedfunctionmyFunc(){
echo"MyClass:
:
myFunc()\n";
}
}
classOtherClassextendsMyClass
{
//覆盖父类中的方法
publicfunctionmyFunc()
{
//但仍然可以调用已被覆盖的方法
parent:
:
myFunc();
echo"OtherClass:
:
myFunc()\n";
}
}
$class=newOtherClass();
$class->myFunc();
?
>
九、小结
PHP中用class来定义类,用new实例化对象,用extends继承类,不过只能单继承,属性和方法有public、private和protected做访问控制,默认为public,在类里定义常量不需要\$,用:
:
范围解析符可以调用父类的方法,访问类的静态变量、静态方法和常量。
十、练习
请定义一个动物类,然后定义一个小狗类继承动物类,里面定义一个吠叫的方法,最后实例化一条小狗,调用它吠叫的方法。