PHP学习-面向对象
2015-12-11 16:38
621 查看
本文大概介绍php中面向对象涉及的一些基础知识。主要以例子为主,文字方面的描述可能会欠缺点。有些知识点会在不同的例子中穿插。
如果不正确的地方,忘包涵。
注意在php中,继承只能继承自一个父类,不能同时继承多个父类。
下面这个例子是,Child1继承自Base2,Base2继承自Base1。Child1中可以引用Base1与Base2中定义的属性。
1.静态属性用于保存类的公有数据,在类的不同实例化对象中访问的值都是相同的
2.静态成员不需要实例化就可以进行访问,通过类的名称在类定义外访问静态成员
3.静态方法里面只能访问静态属性
4.类的内部可以使用self::或static::进行访问,在子类里面可以通过parent::来访问父类的静态属性或方法
在类中都需要具体实现。
不能用接口来实例化对象,如下操作会报错。
如果不想在程序结束时才调用析构方法,而是在之前调用该怎么处理呢。可以为对象赋值null来实现。
注意使用$obj2=$obj1时,如果修改任一对象里面的值,都会影响另外一个对象,如果不想有值篡改的复制,应该使用clone方法,后面会说。
以上的2个方法可以用于方法的重载(overloading),同一方法的名称调用可以对应不同的方法实现。
当获取对象不存在的属性的时候会调用__get()。
直接clone一个对象的话,新对象里面的值与原来的一样,但是可能想在clone的时候对某些属性进行改变,就可以在__chone实现。
如果不正确的地方,忘包涵。
继承
任何语言的面向对象处理,都离不开继承这个话题,所谓继承就是一个子类继承父类的所有特性,同时子类可以还可以添加自己的一些特性。注意在php中,继承只能继承自一个父类,不能同时继承多个父类。
1.单层继承,子类的上面只有一个父类
<?php /** * 父类Base1 */ class Base1 { /** * 父类1的属性 * 属性名为$AttrBase1 * @var string */ public $AttrBase1; /** * 构造函数,实例化对象时调用 * @param string $AttrBase1 属性名 */ function __construct($AttrBase1) { $this->AttrBase1 = $AttrBase1; } /** * 父类1的方法 * 输出属性$Base1name的值 */ public function OutPut() { echo 'Base1 父类属性=' . $this->AttrBase1 . '<br>'; } } /** * 子类Child1,继承自父类Base1 * 子类Child1中没有定义任何属性与方法,但是它包含了Base1的所有元素,包括构造函数 */ class Child1 extends Base1 { } //实例化一个Child1对象,调用了父类的构造方法把值赋给了$AttrBase1 $objChild1 = new Child1("父类属性"); $objChild1->OutPut(); //输出【Base1 父类属性=父类属性】 /** * 子类Child2,继承自父类Base2 * 子类Child2中增加了如下特性: * 自己的属性$AttrChild1 * 自己的方法ChildOutPut * 自己的构造函数,同时还调用父类的构造函数 */ class Child2 extends Base1 { /** * 子类自有的属性 * 属性名为$AttrChild1 * @var string */ public $AttrChild1; /** * 子类的构造函数 * @param string $AttrBase1 父类属性名 * @param string $AttrChild1 子类属性名 */ function __construct($AttrBase1, $AttrChild1) { //为自身的属性赋值 $this->AttrChild1 = $AttrChild1; //调用父类的构造函数为父类中的属性赋值 parent::__construct($AttrBase1); } /** * 子类自身的方法 */ public function ChildOutPut() { echo 'Child2 父类属性=' . $this->AttrBase1 . ' 子类属性=' . $this->AttrChild1 . '<br>'; } } //实例化一个Child2对象,并初始化了父类与子类的属性,调用子类自己的方法进行了输出 $objChild2 = new Child2("父类属性", "子类属性"); $objChild2->ChildOutPut(); //输出【Child2 父类属性=父类属性 子类属性=子类属性】 ?>
2.多层继承,子类的上面有多个父类(父类也是继承是其他类)
在实际使用中,比较常见的就是这种继承,对象需要多次进行归纳,这样才能让代码维护的比较好。下面这个例子是,Child1继承自Base2,Base2继承自Base1。Child1中可以引用Base1与Base2中定义的属性。
/** * 父类Base1 */ class Base1 { /** * * @var string $AttrBase1 Base1属性 */ public $AttrBase1; } /** * 父类Base2 */ class Base2 extends Base1 { /** * * @var string $AttrBase2 Base2属性 */ Public $AttrBase2; } /** * 子类Child1 */ class Child1 extends Base2 { /** * * @var string $AttrChild1 Child属性 */ public $AttrChild1; /** * 子类构造方法,可以同时访问2个父类中的属性 * @param string $AttrBase1 Base1属性 * @param string $AttrBase2 Base2属性 * @param string $AttrChild1 Child1属性 */ function __construct($AttrBase1, $AttrBase2, $AttrChild1) { $this->AttrBase1 = $AttrBase1; $this->AttrBase2 = $AttrBase2; $this->AttrChild1 = $AttrChild1; } /** * 输出父类及子类中的属性 */ public function OutPut() { echo 'Base1属性=' . $this->AttrBase1 . ' Base2属性=' . $this->AttrBase2 . ' Child1属性=' . $this->AttrChild1 . '<br>'; } } //这里有个注意点,当用双引号传入如下参数时会报错 //因为在双引号中有$符号的会当做变量解析,但是$AttrBase1并没有定义 $objChild1 = new Child1('$AttrBase1', '$AttrBase2', '$AttrChild1'); $objChild1->OutPut();
类中属性与方法的访问控制
在定义类里面的属性或者方法时,可以在它们前面加上一些前缀,对属性或方法的方法进行控制。主要有3种控制方法,如下所列:1.public
公有类成员,可以在任何地方进行访问(定义该成员的类【自身】,该类的子类,其他类)。/** * Base类 */ class Base { /** * * @var string $AttrBase 公有属性 */ public $AttrBase; /** * 构造函数 */ function __construct() { $this->AttrBase = 'AttrBase'; } /** * 公有方法 */ public function BaseFunction() { echo '属性=' . $this->AttrBase . '<br>'; } } //实例化Base类 $objBase = new Base(); //在类的外部访问类的public方法 $objBase->BaseFunction(); //在类的外部访问类的public属性 echo '访问Base的public属性=' . $objBase->AttrBase . '<br>'; /** * Child类 */ class Child extends Base { /** * 子类构造函数 */ function __construct() { //在子类里面访问父类的public属性 $this->AttrBase = 'AttrChild'; } } $objChild = new Child(); //在子类的外部访问父类的public方法 $objChild->BaseFunction(); //在子类的外部访问父类的public属性 echo '访问Base的public属性=' . $objChild->AttrBase . '<br>';
2.protected
受保护的成员,可以在定义该成员的类的内部访问或者在子类的内部访问,不能在类的外部进行访问。/** * Base类 */ class Base { /** * * @var string $AttrBase 受保护属性 */ protected $AttrBase; /** * 构造函数 */ function __construct() { $this->AttrBase = 'AttrBase'; } /** * 公有方法 */ public function BaseFunction() { //在自身类里面访问protected属性 echo '属性=' . $this->AttrBase . '<br>'; } } //实例化Base类 $objBase = new Base(); //在类的外部访问类的public方法 $objBase->BaseFunction(); //不能在类的外部访问类的protected属性(会报错) //echo '访问Base的protected属性=' . $objBase->AttrBase . '<br>'; /** * Child类 */ class Child extends Base { /** * 子类构造函数 */ function __construct() { //在子类的内部访问父类protected属性 $this->AttrBase = "ChildClass"; } public function ChildFunction() { //在子类的内部访问父类protected属性 echo '子类属性=' . $this->AttrBase . '<br>'; } } $objChild = new Child(); //通过子类的public函数访问父类的protected属性 $objChild->ChildFunction();
3.private
私有的类成员,只能在定义成员的类的内部进行访问,不能在子类中访问,也不能在外部进行访问。/** * Base类 */ class Base { /** * * @var string $AttrBase 私有属性 */ private $AttrBase; /** * 构造函数 */ function __construct() { $this->AttrBase = 'AttrBase'; } /** * 公有方法 */ public function BaseFunction() { //在自身类里面访问private属性 echo '属性=' . $this->AttrBase . '<br>'; } } //实例化Base类 $objBase = new Base(); //通过类的public方法类的private属性 $objBase->BaseFunction(); //不能在类的外部访问类的private属性(会报错) //echo '访问Base的private属性=' . $objBase->AttrBase . '<br>'; class Child extends Base { /** * 子类的构造函数 */ function __construct() { //子类里面不能访问父类的private属性(不能给父类的AttrBase属性赋值) //在这里会在子类里面创建一个AttrBase属性 $this->AttrBase = 'child'; } /** * 子类方法 */ public function ChildFunction() { echo $this->AttrBase . '<br>'; } } $objChild1 = new Child(); //调用父类方法输出为空,因为在构造函数中不能给父类属性赋值 $objChild1->BaseFunction(); //调用子类方法有输出,因为在子类中创建了AttrBase变量 $objChild1->ChildFunction(); //子类中有了AttrBase这个属性 echo $objChild1->AttrBase . '<br>';
Static(静态)关键字
static关键字大概有如下属性1.静态属性用于保存类的公有数据,在类的不同实例化对象中访问的值都是相同的
2.静态成员不需要实例化就可以进行访问,通过类的名称在类定义外访问静态成员
3.静态方法里面只能访问静态属性
4.类的内部可以使用self::或static::进行访问,在子类里面可以通过parent::来访问父类的静态属性或方法
/** * Base类 */ class Base { /** * * @var static string $AttrStatic 静态属性 */ public static $AttrStatic = 'StaticAttr'; /** * * @var string $AttrGen 常规属性 */ private $AttrGen = 'AttrGen'; /** * 输出静态属性 */ public function EchoStatic() { echo '静态属性self访问=' . self::$AttrStatic . '<br>'; echo '静态属性static访问=' . static::$AttrStatic . '<br>'; } /** * 静态方法输出静态属性 */ public static function EchoGen() { //静态方法里面只能访问静态属性 echo '静态方法里面方法静态属性=' . self::$AttrStatic . '<br>'; //静态方法里面不能访问非静态属性,会报错 //echo '静态方法里面方法静态属性=' . $this->AttrGen . '<br>'; } } //实例化对象$objBase1,输出StaticAttr $objBase1 = new Base(); $objBase1->EchoStatic(); //实例化对象$objBase2,也输出输出StaticAttr $objBase2 = new Base(); $objBase2->EchoStatic(); //在外部通过类名加::访问类里面的静态方法或属性 Base::EchoGen(); echo '类的外部通过Base::AttrStatic访问类的静态属性=' . Base::$AttrStatic . '<br>'; //修改类的静态属性 Base::$AttrStatic = 'StaticAttr change'; echo '类的外部修改类的静态属性<br>'; Base::EchoGen(); /** * Child子类 */ class Child extends Base { /** * 输出父类中的静态属性 */ public function EchoParentStaticAttr() { echo 'Child子类中访问父类的静态方法=' . parent::$AttrStatic . '<br>'; } } $objChild = new Child(); $objChild->EchoParentStaticAttr();
重写(overwrite)与重载(overload)
1.重写
子类重写了父类的同名方法,子类需要根据需求对父类中的方法进行一些自己的处理。/** * Base类 */ class Base { /** * 父类OutPut方法 */ public function OutPut() { echo 'Base类的OutPut方法' . '<br>'; } } /** * Child子类 */ class Child extends Base { /** * 子类OutPut方法,覆盖父类的OutPut方法 */ public function OutPut() { echo 'Base类的OutPut方法在子类中被覆盖' . '<br>'; } } $objChild = new Child(); $objChild->OutPut();
2.重载(overload)
相同的方法名的方法,但是根据传进来的不同参数类型或不同参数个数,执行不同的方法。c#可以实现,在php中不允许有同名的方法,这边借用__call来实现一个重载。/** * Base类 */ class Base { /** * 当实例化的对象访问不存在的函数时调用 * @param type $name 函数名 * @param type $arguments 参数个数 */ function __call($name, $arguments) { switch ($name) { case "OutPut": if (count($arguments) == 1) { //如果只有一个参数 echo '一个参数' . '<br>'; } else if (count($arguments) == 2) { //如果只有二个参数 echo '二个参数' . '<br>'; } else { } break; default: break; } } } $objBase = new Base(); //输出一个参数 $objBase->OutPut(1); //输出二个参数 $objBase->OutPut(1, 2);
Final关键字
从final的字面意思来看,就是最终的意思,它所表达的就是某个类不能被继承或某个函数不能被重写。1.final类
/** * Base类,有final修饰不能被继承 */ final class Base { /** * * @var int $AttrBase Base属性 */ public $AttrBase = 1; } /** * 这里会报错,因为Base类为final的,不能被继承 */ class Child extends Base { }
2.final方法
/** * Base类 */ class Base { /** * final方法,在子类中不能被重写 */ final public function FinalFunction() { echo 'base final function'; } /** * 非final方法,在子类中可以被重写 */ public function OtherFunction() { echo 'base other function'; } } /** * Child继承自Base */ class Child extends Base { /** * 报错,不能重写父类的final方法 */ public function FinalFunction() { echo 'child final function'; } /** * 不报错,可以重写父类的方法 */ public function OtherFunction() { echo 'child other function'; } }
接口
interface关键字用于定义接口,接口里面不需要有方法的具体实现,而是在使用的它的类中实现。可以使用implements关键字来实现某个接口,接口中的所有方法在类中都需要具体实现。
/** * Say接口 */ interface Say { /** * 说中文 * @param string $word 说的话 */ public function SayChinese($word); /** * 说英文 * @param string $word 说的话 */ public function SayEnglish($word); //会报错,接口中不能定义protected方法 //protected function ProtectedSay($word) ; //会报错,接口中不能定义private方法 //private function PrivateSay($word) ; } /** * Human继承自接口Say,需要具体实现接口里面的SayChinese与SayEnglish方法 * 这里注意,在实现接口里面的方法的时候,方法的前缀只能是public */ class Human implements Say { /** * 具体实现SayChinese方法 * @param string $word */ public function SayChinese($word) { echo 'say chinese ' . $word . '<br>'; } /** * 具体实现SayEnglish方法 * @param string $word */ public function SayEnglish($word) { echo 'say english ' . $word . '<br>'; } } /** * Woman继承自Human */ class Woman extends Human { /** * woman说话 */ public function WomanSay() { echo $this->SayChinese('你好'); echo $this->SayEnglish('hello'); } } $objWoman = new Woman(); $objWoman->WomanSay();
不能用接口来实例化对象,如下操作会报错。
/** * Say接口 */ interface Say { /** * 说中文 * @param string $word 说的话 */ public function SayChinese($word); /** * 说英文 * @param string $word 说的话 */ public function SayEnglish($word); } //这里会报错,不能通过接口实例化对象 $objSay = new Say();可以使用instanceof关键字来判断某个对象是否实现了某个接口。
/** * Say接口 */ interface Say { /** * 说中文 * @param string $word 说的话 */ public function SayChinese($word); /** * 说英文 * @param string $word 说的话 */ public function SayEnglish($word); } /** * WomanSay继承接口Say */ class WomanSay implements Say { public function SayChinese($word) { echo 'chinese'; } public function SayEnglish($word) { echo 'english'; } } $objWomanSay = new WomanSay(); //这里输出true,$objWomanSay实现了Say接口 var_dump($objWomanSay instanceof Say);接口可以通过extends来继承别的接口。
/** * Say接口 */ interface Say { /** * 说中文 * @param string $word 说的话 */ public function SayChinese($word); /** * 说英文 * @param string $word 说的话 */ public function SayEnglish($word); } /** * HumanSay接口继承自Say */ interface HumanSay extends Say { /** * 打招呼 */ public function SayHello($word); } /** * WomanSay继承接口Say */ class WomanSay implements HumanSay { //SayChinese具体实现 public function SayChinese($word) { echo 'chinese' . '<br>'; } //SayEnglish public function SayEnglish($word) { echo 'english' . '<br>'; } //SayHello public function SayHello($word) { echo 'hello' . '<br>'; } } $objWomanSay = new WomanSay(); $objWomanSay->SayChinese(''); $objWomanSay->SayEnglish(''); $objWomanSay->SayHello('');
多态
对接口的不同实现类中,同一个方法的具体实现不一样,就叫做多态。/** * 接口Say */ interface Say { //接口方法,SayWord public function SayWord(); } /** * China继承自接口Say */ class China implements Say { /** * China-SayWord具体实现 */ public function SayWord() { echo 'say chinese' . '<br>'; } } /** * English继承自接口Say */ class English implements Say { /** * English-SayWord具体实现 */ public function SayWord() { echo 'say english' . '<br>'; } } //China与English,对SayWord的方法具体实现不同 $objChina = new China(); $objEnglish = new English(); $objChina->SayWord(); $objEnglish->SayWord();
抽象类
abstract用于定义抽象类,抽象类中可以有抽象方法(在方法前增加abstract前缀,不需要具体实现)或者普通方法。可以使用extends关键字来继承抽象类,在子类中需要具体实现抽象类中的抽象方法。/** * 抽象类Human */ abstract class Human { /** * 抽象方法Say,可以用public修饰 */ abstract public function Say(); //会报错,抽象方法不能用private修饰 //abstract private function PrivateSay(); /** * 抽象方法ProtectedSay,可以用protected修饰 */ abstract protected function ProtectedSay(); /** * 普通方法 */ public function GenalFunction() { echo 'GenalFunction' . '<br>'; } } /** * Woman继承自抽象类 * 这里需要注意的: * 1.如果抽象方法为public修饰,在具体实现时也必须是public * 2.如果抽象方法为protected修饰,在具体实现时可以为public或protected */ class Woman extends Human { /** * 抽象方法Say的具体实现 */ public function Say() { echo 'Say' . '<br>'; } /** * 抽象方法ProtectedSay的具体实现 */ protected function ProtectedSay() { echo 'ProtectedSay' . '<br>'; } } $objWoman = new Woman(); $objWoman->Say(); //会报错,protected方法在类的外部不能访问 //$objWoman->ProtectedSay(); $objWoman->GenalFunction();抽象类同样可以用extends来继承别的抽象类。
/** * 抽象类Human */ abstract class Human { /** * 抽象方法Say,可以用public修饰 */ abstract public function Say(); //会报错,抽象方法不能用private修饰 //abstract private function PrivateSay(); /** * 抽象方法ProtectedSay,可以用protected修饰 */ abstract protected function ProtectedSay(); /** * 普通方法 */ public function GenalFunction() { echo 'GenalFunction' . '<br>'; } } /** * 抽象类可以继承别的抽象类 */ abstract class Woman extends Human { /** * 生小孩的方法 */ abstract public function HaveBaby(); } /** * Woman继承自抽象类 * 这里需要注意的: * 1.如果抽象方法为public修饰,在具体实现时也必须是public * 2.如果抽象方法为protected修饰,在具体实现时可以为public或protected */ class WomanClass extends Woman { /** * 抽象方法Say的具体实现 */ public function Say() { echo 'Say' . '<br>'; } /** * 抽象方法ProtectedSay的具体实现 */ public function ProtectedSay() { echo 'ProtectedSay' . '<br>'; } /** * 抽象方法HaveBaby的具体实现 */ public function HaveBaby() { echo 'HaveBaby' . '<br>'; } } $objWoman = new WomanClass(); $objWoman->Say(); $objWoman->ProtectedSay(); $objWoman->GenalFunction(); $objWoman->HaveBaby();
面向对象中一些有趣的方法
1.__construct与__destruct
构造方法__construct在为一个类实例化对象时会调用,可以在构造方法里面为类的某些属性赋值或做某些初始化操作。/** * Base类 */ class Base { /** * * @var string $AttrBase 属性 */ private $AttrBase; /** * 初始化方法,在使用对象之前进行相关的初始化处理 */ private function Init() { echo '初始化实例,通过参数$AttrBase=' . $this->AttrBase . '<br>'; } /** * 构造方法,在实例化对象时调用 * @param type $AttrBase */ function __construct($AttrBase) { //为类的属性赋值 $this->AttrBase = $AttrBase; $this->Init(); } } //实例化对象时传入参数,会调用__construct为类的私有属性赋值 $objBase=new Base('hello world');析构方法__destruct在程序的结束时会被调用,可以在此方法里面来释放使用到的一些资源。
/** * Base类 */ class Base { /** * * @var string $AttrBase 属性 */ private $AttrBase; /** * 初始化方法,在使用对象之前进行相关的初始化处理 */ private function Init() { echo '初始化实例,通过参数$AttrBase=' . $this->AttrBase . '<br>'; } /** * 构造方法,在实例化对象时调用 * @param type $AttrBase */ function __construct($AttrBase) { //为类的属性赋值 $this->AttrBase = $AttrBase; $this->Init(); } /** * 析构方法,程序结束时调用 */ function __destruct() { $this->AttrBase = null; echo '释放属性资源$AttrBase.$AttrBase=' . $this->AttrBase . '<br>'; } } //实例化对象时传入参数,会调用__construct为类的私有属性赋值 $objBase = new Base('hello world'); //可以看到$AttrBase的值被置为空了 //在程序结束时输出了文字【释放属性资源$AttrBase.$AttrBase=】
如果不想在程序结束时才调用析构方法,而是在之前调用该怎么处理呢。可以为对象赋值null来实现。
/** * Base类 */ class Base { /** * * @var string $AttrBase 属性 */ private $AttrBase; /** * 初始化方法,在使用对象之前进行相关的初始化处理 */ private function Init() { echo '初始化实例,通过参数$AttrBase=' . $this->AttrBase . '<br>'; } /** * 构造方法,在实例化对象时调用 * @param type $AttrBase */ function __construct($AttrBase) { //为类的属性赋值 $this->AttrBase = $AttrBase; $this->Init(); } /** * 析构方法,程序结束时调用 */ function __destruct() { $this->AttrBase = null; echo '释放属性资源$AttrBase.$AttrBase=' . $this->AttrBase . '<br>'; } } //实例化对象时传入参数,会调用__construct为类的私有属性赋值 $objBase = new Base('hello world'); //通过把对象设置为null来提前调用析构方法 $objBase=null; //可以看到在下面输出文字之前就已经调用了类Base的析构方法了 echo '我才是程序的结束。';这里还有个有趣的现象,如果使用$obj2=$obj1来把$obj1的值赋给$obj2的话,在将$obj1=null时并不会调用析构方法。因为$obj1与$obj2为不同引用,在$obj1=null后$obj2还对类Base有使用,所以会调用析构方法。除非把$obj2=null或者到程序结束才会调用析构方法。
注意使用$obj2=$obj1时,如果修改任一对象里面的值,都会影响另外一个对象,如果不想有值篡改的复制,应该使用clone方法,后面会说。
/** * Base类 */ class Base { /** * * @var string $AttrBase 属性 */ private $AttrBase; /** * 初始化方法,在使用对象之前进行相关的初始化处理 */ private function Init() { echo '初始化实例,通过参数$AttrBase=' . $this->AttrBase . '<br>'; } /** * 构造方法,在实例化对象时调用 * @param type $AttrBase */ function __construct($AttrBase) { //为类的属性赋值 $this->AttrBase = $AttrBase; $this->Init(); } /** * 析构方法,程序结束时调用 */ function __destruct() { $this->AttrBase = null; echo '释放属性资源$AttrBase.$AttrBase=' . $this->AttrBase . '<br>'; } } //实例化对象时传入参数,会调用__construct为类的私有属性赋值 $objBase = new Base('hello world'); //将$objBase赋值给$objBase1 $objBase1=$objBase; //在将$objBase=null时并不会调用析构方法(在程序结束才会调用) $objBase=null; //但是如果也将$objBase1=null那么就会在程序结束之前调用析构方法了 //$objBase1=null; //可以看到在下面输出文字之前就已经调用了类Base的析构方法了 echo '我才是程序的结束。<br>';当使用$obj2=&$obj1赋值时,它们指向的相同引用,在将任一对象赋值为null时都会调用析构方法。
/** * Base类 */ class Base { /** * * @var string $AttrBase 属性 */ private $AttrBase; /** * 初始化方法,在使用对象之前进行相关的初始化处理 */ private function Init() { echo '初始化实例,通过参数$AttrBase=' . $this->AttrBase . '<br>'; } /** * 构造方法,在实例化对象时调用 * @param type $AttrBase */ function __construct($AttrBase) { //为类的属性赋值 $this->AttrBase = $AttrBase; $this->Init(); } /** * 析构方法,程序结束时调用 */ function __destruct() { $this->AttrBase = null; echo '释放属性资源$AttrBase.$AttrBase=' . $this->AttrBase . '<br>'; } } //实例化对象时传入参数,会调用__construct为类的私有属性赋值 $objBase = new Base('hello world'); //通过如下方式,将$objBase赋值给$objBase1 $objBase1=&$objBase; //在将$objBase=null或$objBase1=null时都会调用析构方法 //$objBase=null; $objBase1=null; //可以看到在下面输出文字之前就已经调用了类Base的析构方法了 echo '我才是程序的结束。<br>';
2.__tostring
当一个对象被当作字符串使用时,会调用这个方法,比如echo $obj。/** * Base类 */ class Base { /** * 在对象被当作字符串使用时调用 * @return string */ function __toString() { echo 'haha<br>'; //最后必须有return处理 return '调用了__toString方法<br>'; } } $objBase = new Base(); //如果Base中没有__toString的话,此处就会报错 echo $objBase;
3.__invoke
当对象被方法来调用时调用,比如$obj(1)。/** * Base类 */ class Base { /** * 对象被当作方法来使用时调用 */ function __invoke() { //将传入的参数合并为字符串 echo '传入方法的参数=' . implode(',', func_get_args()); } } $objBase = new Base(); //如果Base中没有__invoke的话,此处就会报错 $objBase(4, 5, 6);
4.__call与__callStatic
当调用对象不存在的方法时,__call会调用。/** * Base类 */ class Base { /** * 当调用的方法在对象中不存在时 * @param string $name 方法名 * @param array $arguments 参数 */ function __call($name, $arguments) { echo '调用了不存在的方法' . $name . ',使用了参数=' . implode(' ', $arguments) . '<br>'; } } $objBase=new Base(); //输出【调用了不存在的方法Say,使用了参数=I see I come I conquer】 $objBase->Say('I see','I come','I conquer');同理当调用对象不存在的静态方法时,__callStatic会调用。
/** * Base类 */ class Base { /** * 当调用的静态方法在对象中不存在时 * 因为需要在外部调用所以需要用public修饰 * @param string $name 方法名 * @param array $arguments 参数 */ public static function __callStatic($name, $arguments) { echo '调用了不存在的静态方法' . $name . ',使用了参数=' . implode(' ', $arguments) . '<br>'; } } //输出【调用了不存在的静态方法Say,使用了参数=I see I come I conquer】 Base::Say('I see', 'I come', 'I conquer');
以上的2个方法可以用于方法的重载(overloading),同一方法的名称调用可以对应不同的方法实现。
5.__set与__get
当给不存在的属性赋值时会调用__set()方法。实际应用中可以在类中定义一个数组来存放相关属性。/** * Base类 */ class Base { /** * 用于保存不存在的属性 * @var array $arrayAttr */ private $arrayAttr = array(); /** * 设置类中不存在的属性时调用 * @param type $name 属性名 * @param type $value 属性值 */ function __set($name, $value) { $this->arrayAttr[$name] = $value; } /** * 输出属性数组现有值 */ public function OutPutAttr() { echo '属性数组现有值:'; foreach ($this->arrayAttr as $value) { echo $value . ' '; } echo '<br>'; } } $objBase = new Base(); $objBase->attr1 = "i see"; //输出【属性数组现有值:i see 】 $objBase->OutPutAttr(); $objBase->attr2 = "i come"; //输出【属性数组现有值:i see i come 】 $objBase->OutPutAttr(); $objBase->attr3 = "i conquer"; //输出【属性数组现有值:i see i come i conquer 】 $objBase->OutPutAttr();
当获取对象不存在的属性的时候会调用__get()。
/** * Base类 */ class Base { /** * 用于保存不存在的属性 * @var array $arrayAttr */ private $arrayAttr = array(); /** * 设置类中不存在的属性时调用 * @param type $name 属性名 * @param type $value 属性值 */ function __set($name, $value) { $this->arrayAttr[$name] = $value; } /** * 当获取对象不存在的属性时会调用 * @param type $name 属性名 * @return string 返回值 */ function __get($name) { //如果属性已经设置过,则返回对应的属性值,否则返回提示信息 if(array_key_exists($name, $this->arrayAttr)){ return $this->arrayAttr[$name]; } else{ return '属性不存在'; } } /** * 输出属性数组现有值 */ public function OutPutAttr() { echo '属性数组现有值:'; foreach ($this->arrayAttr as $value) { echo $value . ' '; } echo '<br>'; } } $objBase = new Base(); //////设置属性 echo '设置属性<br>'; $objBase->attr1 = "i see"; //输出【属性数组现有值:i see 】 $objBase->OutPutAttr(); $objBase->attr2 = "i come"; //输出【属性数组现有值:i see i come 】 $objBase->OutPutAttr(); $objBase->attr3 = "i conquer"; //输出【属性数组现有值:i see i come i conquer 】 $objBase->OutPutAttr(); //////获取属性 echo '获取属性<br>'; echo $objBase->attr1.'<br>'; echo $objBase->attr4.'<br>';
6.__isset()与__unset()
当对不可访问的属性调用isset()时会调用__isset()。/** * Base类 */ class Base { /** * 用于保存不存在的属性 * @var array $arrayAttr */ private $arrayAttr = array(); /** * 设置类中不存在的属性时调用 * @param type $name 属性名 * @param type $value 属性值 */ function __set($name, $value) { $this->arrayAttr[$name] = $value; } /** * 当获取对象不存在的属性时会调用 * @param type $name 属性名 * @return string 返回值 */ function __get($name) { //如果属性已经设置过,则返回对应的属性值,否则返回提示信息 if (array_key_exists($name, $this->arrayAttr)) { return $this->arrayAttr[$name]; } else { return '属性不存在'; } } /** * 检查某个属性是否已设置 * @param type $name 属性名称 */ function __isset($name) { if (array_key_exists($name, $this->arrayAttr)) { return true; } else { return false; } } /** * 输出属性数组现有值 */ public function OutPutAttr() { echo '属性数组现有值:'; foreach ($this->arrayAttr as $value) { echo $value . ' '; } echo '<br>'; } } $objBase = new Base(); //////设置属性 echo '设置属性<br>'; $objBase->attr1 = "i see"; //输出【属性数组现有值:i see 】 $objBase->OutPutAttr(); $objBase->attr2 = "i come"; //输出【属性数组现有值:i see i come 】 $objBase->OutPutAttr(); $objBase->attr3 = "i conquer"; //输出【属性数组现有值:i see i come i conquer 】 $objBase->OutPutAttr(); //检查属性 //属性attr1已有,返回true echo var_dump(isset($objBase->attr1)); //属性attr4没有,返回false echo var_dump(isset($objBase->attr4));当对不可访问的属性调用unset()时会调用__unset()。
/** * Base类 */ class Base { /** * 用于保存不存在的属性 * @var array $arrayAttr */ private $arrayAttr = array(); /** * 设置类中不存在的属性时调用 * @param type $name 属性名 * @param type $value 属性值 */ function __set($name, $value) { $this->arrayAttr[$name] = $value; } /** * 当获取对象不存在的属性时会调用 * @param type $name 属性名 * @return string 返回值 */ function __get($name) { //如果属性已经设置过,则返回对应的属性值,否则返回提示信息 if (array_key_exists($name, $this->arrayAttr)) { return $this->arrayAttr[$name]; } else { return '属性不存在'; } } /** * 检查某个属性是否已设置 * @param type $name 属性名称 */ function __isset($name) { if (array_key_exists($name, $this->arrayAttr)) { return true; } else { return false; } } /** * 删除某个属性 * @param type $name 属性名 */ function __unset($name) { if (array_key_exists($name, $this->arrayAttr)) { unset($this->arrayAttr[$name]); } } /** * 输出属性数组现有值 */ public function OutPutAttr() { echo '属性数组现有值:'; foreach ($this->arrayAttr as $value) { echo $value . ' '; } echo '<br>'; } } $objBase = new Base(); //////设置属性 echo '设置属性<br>'; $objBase->attr1 = "i see"; //输出【属性数组现有值:i see 】 $objBase->OutPutAttr(); $objBase->attr2 = "i come"; //输出【属性数组现有值:i see i come 】 $objBase->OutPutAttr(); $objBase->attr3 = "i conquer"; //输出【属性数组现有值:i see i come i conquer 】 $objBase->OutPutAttr(); //检查属性 //属性attr1已有,返回true echo var_dump(isset($objBase->attr1)); //删除attr1 unset($objBase->attr1); //属性attr1被删除了,返回false echo var_dump(isset($objBase->attr1));
7.__chone
当某个对象被clone时调用。直接clone一个对象的话,新对象里面的值与原来的一样,但是可能想在clone的时候对某些属性进行改变,就可以在__chone实现。
/** * Base类 */ class Base { /** * 属性 * @var type $AttrBase */ public $AttrBase; /** * 构造方法 * @param type $AttrBase */ function __construct($AttrBase) { $this->AttrBase = $AttrBase; } /** * 当chone对象是调用 */ function __clone() { $this->AttrBase = 'hello moon'; } } $objBase = new Base('hello world'); //实例化对象 echo $objBase->AttrBase . '<br>'; //clone对象 $objBase1 = clone $objBase; //如果没有__chone则输出的值同$objBase值 //如果有__chone则输出的值为在此方法里为属性新赋的值 echo $objBase1->AttrBase . '<br>';
相关文章推荐
- php内核探索笔记-初窥
- thinkphp裁剪png图片背景不透明
- php 生成验证码
- PHP获得数组的交集与差集
- zhphp framework (十九) pdo数据库抽象类
- zhphp framework (十八) php 验证类
- zhphp framework (十八) session 抽象接口
- ThinkPHP3.1分页时,采用联表查询的处理
- zhphp framework (十七) 模型接口
- dede 相关文章的调用
- 配置文件读取类conf.class.php 单例模式应用
- 经历了一期的项目洗礼的成长
- 织梦自定义专题节点容器模板修正
- PHP下载网页图片
- php中json_decode返回数组或对象
- 我的PHP之旅
- 功能很全的PHP分页类
- ThinkPHP3.2.3完整版中对Auth.class.php的使用
- 织梦dede后台限制简略标题字数的修改
- 如何修改dede文章页上一篇下一篇"没有了"