博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PHP学习-面向对象
阅读量:2426 次
发布时间:2019-05-10

本文共 25560 字,大约阅读时间需要 85 分钟。

本文大概介绍php中面向对象涉及的一些基础知识。主要以例子为主,文字方面的描述可能会欠缺点。有些知识点会在不同的例子中穿插。

如果不正确的地方,忘包涵。

继承

任何语言的面向对象处理,都离不开继承这个话题,所谓继承就是一个子类继承父类的所有特性,同时子类可以还可以添加自己的一些特性。

注意php中继承只能继承自一个父类,不能同时继承多个父类。

1.单层继承,子类的上面只有一个父类

AttrBase1 = $AttrBase1; } /** * 父类1的方法 * 输出属性$Base1name的值 */ public function OutPut() { echo 'Base1 父类属性=' . $this->AttrBase1 . '
'; }}/** * 子类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 . '
'; }}//实例化一个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 . '
'; }}//这里有个注意点,当用双引号传入如下参数时会报错//因为在双引号中有$符号的会当做变量解析,但是$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 . '
'; }}//实例化Base类$objBase = new Base();//在类的外部访问类的public方法$objBase->BaseFunction();//在类的外部访问类的public属性echo '访问Base的public属性=' . $objBase->AttrBase . '
';/** * Child类 */class Child extends Base { /** * 子类构造函数 */ function __construct() { //在子类里面访问父类的public属性 $this->AttrBase = 'AttrChild'; }}$objChild = new Child();//在子类的外部访问父类的public方法$objChild->BaseFunction();//在子类的外部访问父类的public属性echo '访问Base的public属性=' . $objChild->AttrBase . '
';

2.protected

受保护的成员,可以在定义该成员的类的内部访问或者在子类的内部访问,不能在类的外部进行访问。

/** * Base类 */class Base {    /**     *     * @var string $AttrBase 受保护属性     */    protected $AttrBase;    /**     * 构造函数     */    function __construct() {        $this->AttrBase = 'AttrBase';    }    /**     * 公有方法     */    public function BaseFunction() {        //在自身类里面访问protected属性        echo '属性=' . $this->AttrBase . '
'; }}//实例化Base类$objBase = new Base();//在类的外部访问类的public方法$objBase->BaseFunction();//不能在类的外部访问类的protected属性(会报错)//echo '访问Base的protected属性=' . $objBase->AttrBase . '
';/** * Child类 */class Child extends Base { /** * 子类构造函数 */ function __construct() { //在子类的内部访问父类protected属性 $this->AttrBase = "ChildClass"; } public function ChildFunction() { //在子类的内部访问父类protected属性 echo '子类属性=' . $this->AttrBase . '
'; }}$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 . '
'; }}//实例化Base类$objBase = new Base();//通过类的public方法类的private属性$objBase->BaseFunction();//不能在类的外部访问类的private属性(会报错)//echo '访问Base的private属性=' . $objBase->AttrBase . '
';class Child extends Base { /** * 子类的构造函数 */ function __construct() { //子类里面不能访问父类的private属性(不能给父类的AttrBase属性赋值) //在这里会在子类里面创建一个AttrBase属性 $this->AttrBase = 'child'; } /** * 子类方法 */ public function ChildFunction() { echo $this->AttrBase . '
'; }}$objChild1 = new Child();//调用父类方法输出为空,因为在构造函数中不能给父类属性赋值$objChild1->BaseFunction();//调用子类方法有输出,因为在子类中创建了AttrBase变量$objChild1->ChildFunction();//子类中有了AttrBase这个属性echo $objChild1->AttrBase . '
';

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 . '
'; echo '静态属性static访问=' . static::$AttrStatic . '
'; } /** * 静态方法输出静态属性 */ public static function EchoGen() { //静态方法里面只能访问静态属性 echo '静态方法里面方法静态属性=' . self::$AttrStatic . '
'; //静态方法里面不能访问非静态属性,会报错 //echo '静态方法里面方法静态属性=' . $this->AttrGen . '
'; }}//实例化对象$objBase1,输出StaticAttr$objBase1 = new Base();$objBase1->EchoStatic();//实例化对象$objBase2,也输出输出StaticAttr$objBase2 = new Base();$objBase2->EchoStatic();//在外部通过类名加::访问类里面的静态方法或属性Base::EchoGen();echo '类的外部通过Base::AttrStatic访问类的静态属性=' . Base::$AttrStatic . '
';//修改类的静态属性Base::$AttrStatic = 'StaticAttr change';echo '类的外部修改类的静态属性
';Base::EchoGen();/** * Child子类 */class Child extends Base { /** * 输出父类中的静态属性 */ public function EchoParentStaticAttr() { echo 'Child子类中访问父类的静态方法=' . parent::$AttrStatic . '
'; }}$objChild = new Child();$objChild->EchoParentStaticAttr();

重写(overwrite)与重载(overload)

1.重写

子类重写了父类的同名方法,子类需要根据需求对父类中的方法进行一些自己的处理。

/** * Base类 */class Base {    /**     * 父类OutPut方法     */    public function OutPut() {        echo 'Base类的OutPut方法' . '
'; }}/** * Child子类 */class Child extends Base { /** * 子类OutPut方法,覆盖父类的OutPut方法 */ public function OutPut() { echo 'Base类的OutPut方法在子类中被覆盖' . '
'; }}$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 '一个参数' . '
'; } else if (count($arguments) == 2) { //如果只有二个参数 echo '二个参数' . '
'; } 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 . '
'; } /** * 具体实现SayEnglish方法 * @param string $word */ public function SayEnglish($word) { echo 'say english ' . $word . '
'; }}/** * 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' . '
'; } //SayEnglish public function SayEnglish($word) { echo 'english' . '
'; } //SayHello public function SayHello($word) { echo 'hello' . '
'; }}$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' . '
'; }}/** * English继承自接口Say */class English implements Say { /** * English-SayWord具体实现 */ public function SayWord() { echo 'say english' . '
'; }}//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' . '
'; }}/** * Woman继承自抽象类 * 这里需要注意的: * 1.如果抽象方法为public修饰,在具体实现时也必须是public * 2.如果抽象方法为protected修饰,在具体实现时可以为public或protected */class Woman extends Human { /** * 抽象方法Say的具体实现 */ public function Say() { echo 'Say' . '
'; } /** * 抽象方法ProtectedSay的具体实现 */ protected function ProtectedSay() { echo 'ProtectedSay' . '
'; }}$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' . '
'; }}/** * 抽象类可以继承别的抽象类 */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' . '
'; } /** * 抽象方法ProtectedSay的具体实现 */ public function ProtectedSay() { echo 'ProtectedSay' . '
'; } /** * 抽象方法HaveBaby的具体实现 */ public function HaveBaby() { echo 'HaveBaby' . '
'; }}$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 . '
'; } /** * 构造方法,在实例化对象时调用 * @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 . '
'; } /** * 构造方法,在实例化对象时调用 * @param type $AttrBase */ function __construct($AttrBase) { //为类的属性赋值 $this->AttrBase = $AttrBase; $this->Init(); } /** * 析构方法,程序结束时调用 */ function __destruct() { $this->AttrBase = null; echo '释放属性资源$AttrBase.$AttrBase=' . $this->AttrBase . '
'; }}//实例化对象时传入参数,会调用__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 . '
'; } /** * 构造方法,在实例化对象时调用 * @param type $AttrBase */ function __construct($AttrBase) { //为类的属性赋值 $this->AttrBase = $AttrBase; $this->Init(); } /** * 析构方法,程序结束时调用 */ function __destruct() { $this->AttrBase = null; echo '释放属性资源$AttrBase.$AttrBase=' . $this->AttrBase . '
'; }}//实例化对象时传入参数,会调用__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 . '
'; } /** * 构造方法,在实例化对象时调用 * @param type $AttrBase */ function __construct($AttrBase) { //为类的属性赋值 $this->AttrBase = $AttrBase; $this->Init(); } /** * 析构方法,程序结束时调用 */ function __destruct() { $this->AttrBase = null; echo '释放属性资源$AttrBase.$AttrBase=' . $this->AttrBase . '
'; }}//实例化对象时传入参数,会调用__construct为类的私有属性赋值$objBase = new Base('hello world');//将$objBase赋值给$objBase1$objBase1=$objBase;//在将$objBase=null时并不会调用析构方法(在程序结束才会调用)$objBase=null;//但是如果也将$objBase1=null那么就会在程序结束之前调用析构方法了//$objBase1=null;//可以看到在下面输出文字之前就已经调用了类Base的析构方法了echo '我才是程序的结束。
';
当使用$obj2=&$obj1赋值时,它们指向的相同引用,在将任一对象赋值为null时都会调用析构方法。

/** * Base类 */class Base {    /**     *     * @var string $AttrBase 属性     */    private $AttrBase;    /**     * 初始化方法,在使用对象之前进行相关的初始化处理     */    private function Init() {        echo '初始化实例,通过参数$AttrBase=' . $this->AttrBase . '
'; } /** * 构造方法,在实例化对象时调用 * @param type $AttrBase */ function __construct($AttrBase) { //为类的属性赋值 $this->AttrBase = $AttrBase; $this->Init(); } /** * 析构方法,程序结束时调用 */ function __destruct() { $this->AttrBase = null; echo '释放属性资源$AttrBase.$AttrBase=' . $this->AttrBase . '
'; }}//实例化对象时传入参数,会调用__construct为类的私有属性赋值$objBase = new Base('hello world');//通过如下方式,将$objBase赋值给$objBase1$objBase1=&$objBase;//在将$objBase=null或$objBase1=null时都会调用析构方法//$objBase=null;$objBase1=null;//可以看到在下面输出文字之前就已经调用了类Base的析构方法了echo '我才是程序的结束。
';

2.__tostring

当一个对象被当作字符串使用时,会调用这个方法,比如echo $obj。

/** * Base类 */class Base {        /**     * 在对象被当作字符串使用时调用     * @return string     */    function __toString() {        echo 'haha
'; //最后必须有return处理 return '调用了__toString方法
'; }}$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) . '
'; }}$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) . '
'; }}//输出【调用了不存在的静态方法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 '
'; }}$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 '
'; }}$objBase = new Base();//设置属性echo '设置属性
';$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 '获取属性
';echo $objBase->attr1.'
';echo $objBase->attr4.'
';

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 '
'; }}$objBase = new Base();//设置属性echo '设置属性
';$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已有,返回trueecho var_dump(isset($objBase->attr1));//属性attr4没有,返回falseecho 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 '
'; }}$objBase = new Base();//设置属性echo '设置属性
';$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已有,返回trueecho var_dump(isset($objBase->attr1));//删除attr1unset($objBase->attr1);//属性attr1被删除了,返回falseecho 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 . '
';//clone对象$objBase1 = clone $objBase;//如果没有__chone则输出的值同$objBase值//如果有__chone则输出的值为在此方法里为属性新赋的值echo $objBase1->AttrBase . '
';

转载地址:http://jodmb.baihongyu.com/

你可能感兴趣的文章
【数据库】SQL之重点知识点总结
查看>>
【计算机网络】计算机网络知识总结
查看>>
【Java】【Web】JavaWeb相关知识总结 2018-9-17
查看>>
【数据库】突破单一数据库的性能限制——数据库-分库分表总结 2018-9-20
查看>>
【Java】Java常用包的功能 2018-09-21
查看>>
【Java】Map接口主要的四个常用实现类 2018-9-22
查看>>
【Java】HttpServletRequest常用方法2012-9-22
查看>>
【Java】【WEB】XML配置和注解配置的区别 2018-9-23
查看>>
【Java】【WEB】servlet线程不安全问题 2018-9-23
查看>>
【计算机网络】【HTTPS】HTTPS通信原理剖析 2018-9-25
查看>>
【java】优先队列问题2018-9-25
查看>>
【Java】【web】【计算机网络】cookie学习总结 2018-9-28
查看>>
【Java】【编程练习】给定一个整数数组A及它的大小n,同时给定要查找的元素val,请返回它在数组中的位置(从0开始),若不存在该元素,返回-1。若该元素出现多次请返回第一个找到的位置.2018-9
查看>>
【Java】【编程练习】输入一个正整数n,求n!(即阶乘)末尾有多少个 0 ? 2018-9-28
查看>>
【Java】【web】【计算机网络】session学习总结 2018-9-28
查看>>
【计算机网络】【WEB】DNS域名解析过程(十步走) 2018-9-28
查看>>
【java】【web】Web组件之间的跳转方式 2018-9-29
查看>>
【Java】【web】Servlet的三大作用域对象 2018-8-29
查看>>
【转载】【计算机网络】【TCP】当我们说"TCP是可靠协议"时,我们真正表达的是什么?
查看>>
【Java】【JVM】Java中JVM内存管理 2018-10-5
查看>>