本文共 25560 字,大约阅读时间需要 85 分钟。
本文大概介绍php中面向对象涉及的一些基础知识。主要以例子为主,文字方面的描述可能会欠缺点。有些知识点会在不同的例子中穿插。
如果不正确的地方,忘包涵。
任何语言的面向对象处理,都离不开继承这个话题,所谓继承就是一个子类继承父类的所有特性,同时子类可以还可以添加自己的一些特性。
注意在php中,继承只能继承自一个父类,不能同时继承多个父类。
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 父类属性=父类属性 子类属性=子类属性】 ?>
在实际使用中,比较常见的就是这种继承,对象需要多次进行归纳,这样才能让代码维护的比较好。
下面这个例子是,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种控制方法,如下所列:
公有类成员,可以在任何地方进行访问(定义该成员的类【自身】,该类的子类,其他类)。
/** * 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 . '';
/** * 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();
私有的类成员,只能在定义成员的类的内部进行访问,不能在子类中访问,也不能在外部进行访问。
/** * 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关键字大概有如下属性
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();
子类重写了父类的同名方法,子类需要根据需求对父类中的方法进行一些自己的处理。
/** * 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();
相同的方法名的方法,但是根据传进来的不同参数类型或不同参数个数,执行不同的方法。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的字面意思来看,就是最终的意思,它所表达的就是某个类不能被继承或某个函数不能被重写。
/** * Base类,有final修饰不能被继承 */final class Base { /** * * @var int $AttrBase Base属性 */ public $AttrBase = 1;}/** * 这里会报错,因为Base类为final的,不能被继承 */class Child extends Base { }
/** * 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();
构造方法__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 '我才是程序的结束。';
当一个对象被当作字符串使用时,会调用这个方法,比如echo $obj。
/** * Base类 */class Base { /** * 在对象被当作字符串使用时调用 * @return string */ function __toString() { echo 'haha'; //最后必须有return处理 return '调用了__toString方法'; }}$objBase = new Base();//如果Base中没有__toString的话,此处就会报错echo $objBase;
当对象被方法来调用时调用,比如$obj(1)。
/** * Base类 */class Base { /** * 对象被当作方法来使用时调用 */ function __invoke() { //将传入的参数合并为字符串 echo '传入方法的参数=' . implode(',', func_get_args()); }}$objBase = new Base();//如果Base中没有__invoke的话,此处就会报错$objBase(4, 5, 6);
/** * 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),同一方法的名称调用可以对应不同的方法实现。
当给不存在的属性赋值时会调用__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.'';
当对不可访问的属性调用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));
当某个对象被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/