PHP学习-面向对象

本文通过实例介绍了PHP面向对象的基础知识,包括继承、属性与方法的访问控制、静态关键字、重写与重载、抽象类、接口及多态等概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

继承

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

注意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>';















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值