摘要:特殊在,方法被對象調(diào)用執(zhí)行時,會自動確定是那個對象調(diào)用的該方法,會使用該對象為方法內(nèi)的賦值構(gòu)造析構(gòu)類,沒有作用域,作用域,只是講,函數(shù)內(nèi)和函數(shù)外。析構(gòu)在對象消失對象被銷毀時,也會自動執(zhí)行一個方法,稱之為析構(gòu)方法。
相關(guān)定義
對象(object):現(xiàn)實(shí)生活中的實(shí)體,在編程語言中的體現(xiàn)。實(shí)體都有屬性和功能。一組數(shù)據(jù),和操作管理這些數(shù)據(jù)的操作,定義在一起就形成了一個實(shí)體,稱之為對象。(屬性和方法的集合)
屬性(property),對象中,對象所擁有的數(shù)據(jù),稱之為對象的屬性。
方法(method):對象中,對象所擁有的管理數(shù)據(jù)的能力,稱之為方法。
在php中,對象通過對類的實(shí)體化形成的對象。
類(class): 對象的模子。 一類的對象抽取出來。一個將對象的行為和屬性的一個抽象。就是一個定義。規(guī)定了對象應(yīng)該有哪些屬性,應(yīng)該有哪些操作(方法)。
實(shí)例化:一個動作,根據(jù)類中所定義的對象的特征,形成一個對象的過程。
注意: php 中,對象一定是通過類的實(shí)例化來的。類的地位,只是得到對象的方法。
可以使用php 預(yù)定義的類。
stdclass . 通過實(shí)例化該類,就可以得到一個對象。
實(shí)例化: 通過關(guān)鍵字new 完成.
class 關(guān)鍵字
class 類名 { 成員 }
在定義一個類的時,需要知道這個類所實(shí)例化的對象,應(yīng)該具有哪些屬性和方法。
增加屬性: 對象所擁有的數(shù)據(jù),就是定義在類中變量。
增加方法: 對象所擁有的操作,可執(zhí)行代碼就是操作.定義在類中的函數(shù).
注意:類中的成員(屬性和方法),需要增加訪問修飾限定符,簡單的增加--public
在聲明成員時,不能直接使用變量,需要使用關(guān)鍵字來聲明
通過類得到對象 ,操作符 new 完成.
實(shí)例化好后,典型的應(yīng)該保存在變量內(nèi)
$stu = new Student();
一個類,可以實(shí)例化多個對象,多個不同的對象
對象操作屬性和方法使用操作符 ->
// 對象 -> 成員 $stu->a; // 10
注意,屬性名前$沒有了
如果存在$, 語法就 變成 屬性名(屬性標(biāo)識符) 由變量充當(dāng),變成了可變屬性的語法
$property_name = "stu_id"; echo $stu->$property_name;
屬性名,同變量名一樣,嚴(yán)格區(qū)分大小寫。
保存數(shù)據(jù)標(biāo)識符,就區(qū)分大小寫。
如果是結(jié)構(gòu)標(biāo)識符,就區(qū)分大小寫。 比如:函數(shù),類,方法名。
訪問方法:
$stu->study();
方法名,不區(qū)分大小寫
方法名,支持可變方法,方法名有變量來代替
類名,可以使用變量來代替。
$class_name = "Student"; $stu = new $class_name;屬性
可以在定義時,為屬性直接設(shè)置初始值,但是必須已經(jīng)存在的數(shù)據(jù)(類似于函數(shù)參數(shù)的默認(rèn)值)
如果沒有默認(rèn)值,則值為null
屬性,每個對象的同名屬性,都可以具有不同的值, 每個對象所擁有的屬性時不同的數(shù)據(jù)空間。
因?yàn)樵趯?shí)例化對象時,php會為每個對象分配一個獨(dú)立的空間,保存對象的屬性
由于,常規(guī)的,每個對象,應(yīng)該擁有不同的屬性值。
建議,在得到該對象時,應(yīng)該對對象所擁有的屬性,進(jìn)行初始化。
方法,也是屬于某個對象。但是通常,方法內(nèi)所操作的數(shù)據(jù),都是該對象所擁有的數(shù)據(jù)。
在使用對象調(diào)用某個方法時,會自動地將當(dāng)前對象傳遞到該方法內(nèi)(類似于參數(shù)的傳遞)。 方法內(nèi),會自動使用變量 $this 來接收這個對象。因此,可以在方法內(nèi),通過$this方法調(diào)用該方法的對象。
如何在方法中,訪問對象,$this
$this,這個對象。調(diào)用該方法的對象。
$this 就是一個方法內(nèi)的局部變量。特殊在,方法被對象調(diào)用執(zhí)行時,PHP會自動確定是那個對象調(diào)用的該方法,會使用該對象為方法內(nèi)的$this賦值
構(gòu)造&析構(gòu)類,沒有作用域, 作用域,只是講,函數(shù)內(nèi)和函數(shù)外。
注意,想訪問到對象的成員(屬性和方法),一定要先找到對象和方法。
class Student { public $stu_id; public $stu_name; public function sayName() { echo $this->stu_name; // zf var_dump($stu_name); // 報(bào)錯 Undefined variable var_dump($GLOBALS["stu_name"]); // 報(bào)錯 Undefined variable } } $stu = new Student(); $stu->stu_id = "16.7.3"; $stu->stu_name = "zf"; $stu->sayName();
類中定義的屬性,不是相當(dāng)于類中定義的方法的全局變量。不能直接在方法中使用屬性變量的形式訪問:
如果直接操作(輸出)這個類名,則不會當(dāng)做類來看待,而是當(dāng)做常量來看待。
構(gòu)造在得到對象時,幾乎都需要,對對象屬性進(jìn)行初始化,而且都是一樣的操作。在一個操作中完成初始化,然后對該方法進(jìn)行多次調(diào)用。
在實(shí)例化類得到對象時被自動地調(diào)用
主要承擔(dān)的工作是初始化對象屬性
對象的屬性初始化
只要得到了對象,對象的屬性就應(yīng)該被賦予新的值。
如果某些屬性,在對象出現(xiàn)時,可以被設(shè)置為某些特定的值。就可以在聲明類時,為聲明的屬性設(shè)置默認(rèn)值。
stu_id = $id; $this->stu_name = $name; }
調(diào)用該方法初始化
stu_id = $id; $this->stu_name = $name; } } $stu1 = new Student; // $stu1->stu_id = 100; // $stu1->stu_name = "李尋歡"; $stu1->init(100,"李尋歡"); var_dump($stu1);
再前進(jìn)一步:
是否可以在實(shí)例化后,自動調(diào)用該初始化方法的方法。
PHP的 oop 機(jī)制,在new完成時,會試著調(diào)用一個叫做 __constructor() 的方法.如果將初始化的代碼,寫到這個方法內(nèi),就可以完成自動初始化。
該方法,在通過類實(shí)例化對象,也叫構(gòu)造對象時,被自動調(diào)用的,常常用于初始化對象,這個方法被叫做 構(gòu)造方法。(此方法,就是比普通方法多了一個自動調(diào)用的功能)
只要得到了對象,對象的屬性就應(yīng)該被賦予新的值
由于不用去調(diào)用這個構(gòu)造函數(shù),如何傳參呢?
在實(shí)例化時,通過在類名后,增加實(shí)例化列表形式,為構(gòu)造函數(shù)方法傳參。stu_id = $id; $this->stu_name = $name; } } $stu1 = new Student(100,"李尋歡");此時,需要注意,實(shí)例化時,類名后,可以增加括號,取決于,該對象的構(gòu)造方法,是否需要參數(shù),如果不需要,則可以省略,或者是一個空括號。如果需要則一定有括號,括號內(nèi)是實(shí)參列表
$stu1 = new Student; $stu2 = new Student(); // 需要參數(shù) $stu2 = new Student("1000","阿飛");構(gòu)造方法的兼容性問題
PHP5,構(gòu)造方法的名字, 就是 __construct(); 在php5之前,構(gòu)造方法名字與類同名。為了兼容,也同時支持這個與類同名的構(gòu)造方法class Student { public function Student ( $id, $name ) { } }如果同時出現(xiàn),如何處理
先寫__construct(); 后寫Student;找,__construct.
先寫Stuendt(); 后寫__construct();
找 __construct. 有一個錯誤提示。
常見的寫法:
public function __construct ( $id, $name ) { $this->Student($id,$name); } public function Student ( $id,$name ) { $this->stu_id = $id; $this->stu_name = $name; }構(gòu)造是這個對象來的時候的方法,對象實(shí)例化類的時候,才形成的。
如果某些屬性,在對象出現(xiàn)時,可以被設(shè)置為某些特定的值。就可以在聲明類時,為聲明的屬性設(shè)置默認(rèn)值
如果沒有定義__construct()可以不用執(zhí)行
析構(gòu)
但是一旦定義了構(gòu)造方法,那么構(gòu)造(實(shí)例化)的過程,一定要包括這個調(diào)用構(gòu)造方法的過程(構(gòu)造方法一定會執(zhí)行)。在對象消失(對象被銷毀時),也會自動執(zhí)行一個方法,稱之為析構(gòu)方法。
析構(gòu)方法名字為 __destruct();
也會自動被調(diào)用。完全取決于這個對象是否被銷毀。該方法,用于釋放對象所占用的額外資源。并不是釋放對象本身.(對象本身,是由垃圾回收機(jī)制去銷毀) 不是對象本身的內(nèi)存空間。
public function __destruct () { // 釋放資源 mysql_close(); }什么情況下,對象會被銷毀:
腳本周期結(jié)束,自動銷毀,幾個對象銷毀幾次。
銷毀保存該對象的變量時:
unset($stu1);
保存對象的變量,被賦值了其他數(shù)據(jù)。 任何新值都可以,甚至是原來類的新對象。都會導(dǎo)致原對象被銷毀。常見的使用是null.表示銷毀對象的含意
$stu = null;對象間的copy&clone對象間的復(fù)制
支持引用傳遞,不用 & 符號, 因此不能通過 = 賦值的形式,得到一個新的對象。克隆 clone
利用已有的對象,得到相同的新對象。
需要使用關(guān)鍵字 clone 完成。
新對象 = clone 舊對象.常見的操作,在克隆對象時,需要對對象的某些特殊屬性進(jìn)行修改。意味著,在克隆的時,需要做一些特殊的處理。
使用 在克隆時,自動調(diào)用的方法, __clone() 來實(shí)現(xiàn)。
自動使用克隆出來的對象,來調(diào)用這個__clone()方法,意味著,該方法內(nèi)的$this,表示新對象;
public function __clone () { // $this 指向克隆對象 $this->stu_id = "1000"; } $stu3 = clone $stu1;PHP中得到新對象兩個方法
實(shí)例化(通過類構(gòu)造對象) ,需要使用構(gòu)造方法對對象進(jìn)行初始化。
克隆(通過對象克隆新對象) ,得到一個屬性值與克隆的就對象一模一樣的對象,但是,可以通過__clone 方法進(jìn)行修改。
魔術(shù)方法
靜態(tài)成員
特定的情況下,會被自動調(diào)用
__ 魔術(shù)方法場景: 學(xué)生類,每個學(xué)生是一個類的對象,需要統(tǒng)計(jì),當(dāng)前已經(jīng)存在幾個學(xué)生?
如何定義這個計(jì)數(shù)器?
不能直接用屬于對象的屬性,每個對象所獨(dú)有的。
應(yīng)該找一個對象所共有的數(shù)據(jù)。
構(gòu)造方法靜態(tài)局部變量,也是不行,原因析構(gòu)時不能使用。public function __construct () { $this->count++; static $count = 0; $count ++; echo $coun; } public function __destruct () { $this->count--; $count--; }應(yīng)該找一個能夠被對象所共有的數(shù)據(jù)并且能夠在多個方法內(nèi)使用的變量。
使用全局變量即可,在方法內(nèi),是可以通過$GLOBALS訪問到全局變量。public function __construct () { $GLOBALS["count"]++; } public function __destruct () { $GLOABLS["count"]--; }全局變量不應(yīng)該屬于任何的對象或者類.$count 與 類 沒有絲毫的邏輯上的聯(lián)系.
應(yīng)該找一個能夠被對象所共有并且能夠在多個方法內(nèi)使用的變量,還應(yīng)該與當(dāng)前的對象類有邏輯的關(guān)系的數(shù)據(jù)?
可以使用類的靜態(tài)成員.靜態(tài)成員,指的是邏輯上被所有對象所共享,屬于類的成員稱之為類的靜態(tài)成員。
靜態(tài)屬性和靜態(tài)方法
靜態(tài)屬性
保存數(shù)據(jù)的是靜態(tài)屬性,執(zhí)行功能的是靜態(tài)方法使用static 關(guān)鍵字聲明的屬性。
該靜態(tài)屬性,在邏輯上,是定義在類上面的屬性。(與定義對象上的屬性對應(yīng)).public static $stu_count = 0;保證一個類,對應(yīng)一個屬性,意味著,該類的所有對象共用這個屬性。
訪問靜態(tài)屬性
通過類來訪問,再利用靜態(tài)訪問符號(雙冒號::,范圍解析操作符)
類::成員
Student::$stu_count++;:: 的訪問稱之為靜態(tài)訪問,相對的箭頭(->)稱為非靜態(tài)訪問(對象訪問)
var_dump(Student::$stu_count);在訪問時,如果是在類內(nèi)訪問:則可以使用self關(guān)鍵字,來代替當(dāng)前類.
self::$stu_count++;注意,$this和self的區(qū)別
$this表示的是這個對象。 $this->
self表示類自己。 self::
parsent當(dāng)前父類 parent::PHP還支持的寫法:
對象也支持靜態(tài)訪問,但是需要使用靜態(tài)訪問符號。容易造成混淆,不建議經(jīng)常使用。$stu3::$stu_count;靜態(tài)方法靜態(tài)方法的邏輯意義,也是定義在類上的方法。同樣,調(diào)用形式,也是通過類:: 來訪問
定義:
public static function sayCount () { echo "run"; }訪問:
Student::sayCount();靜態(tài)方法和非靜態(tài)方法的主要區(qū)別,在于是否可以接收一個對象的執(zhí)行環(huán)境
就是是否可以為方法內(nèi)的$this 是否可以被賦值只有在對象調(diào)用方法時,才能將對象的執(zhí)行環(huán)境傳遞到方法內(nèi),$this才可以被賦值.
Class Student { public static $stu_count = 0; public static function sayCount () { var_dump($this); //報(bào)錯 echo "run"; } } $stu1 = new Student(); Student::sayCount();無論靜態(tài)和非靜態(tài)方法,都是一個函數(shù),找到他并執(zhí)行即可。
一個靜態(tài)方法,只能處理靜態(tài)數(shù)據(jù)(靜態(tài)屬性)public static function sayCount () { echo self::$stu_count; echo "run"; }PHP中特殊的方法訪問問題
靜態(tài)方法應(yīng)該類來調(diào)用,非靜態(tài)方法,應(yīng)該對象調(diào)用。
但是:
無論靜態(tài)還是非靜態(tài),都可以使用類來訪問。
不過如果類靜態(tài)調(diào)用一個非靜態(tài)方法,會報(bào)告一個strict standards 語法不標(biāo)準(zhǔn)的錯誤。
對象也可以都調(diào)用Class Student { public function fn1 () { echo "fn1"; } public static function fn2 () { echo "fn2"; } } $stu1 = new Student(); Student::fn1(); Student::fn2(); $stu1->fn1(); $stu1->fn2();區(qū)別就在于$this上
類常量
只有在使用對象調(diào)用非靜態(tài)方法時,才可以使用方法內(nèi)的$this;
靜態(tài)方法,無論如何也不能對$this做處理
而非靜態(tài)方法,只有確定了對象,才能確定$this的值類中,保存運(yùn)行運(yùn)行周期內(nèi),不變的數(shù)據(jù)。就是常量。
定義
const 關(guān)鍵字
const 常量名 = 常量值
沒有訪問修飾限定符.const PI = 3.14;訪問
類::常量名
把屬性值,固定值,定義成常量。self::PI;常見,類中 屬性的選項(xiàng), 多定義成 常量。
類中可以定義的成員一共有
常量,靜態(tài)屬性,靜態(tài)方法,非靜態(tài)屬性,非靜態(tài)方法
除了以上5個,類中,不能直接出現(xiàn)其他語句,例如echo的執(zhí)行性語句,var_dump(), 等等
簡化一點(diǎn):常量,屬性,方法$this 表示當(dāng)前對象
永遠(yuǎn)表示$this所在類的對象么?
不是,因?yàn)?this的值,不取決于$this所在的類,而是$this所在方法在被調(diào)用時執(zhí)行對象(執(zhí)行環(huán)境)。方法的執(zhí)行環(huán)境(context),當(dāng)前方法是在哪個對象的環(huán)境下執(zhí)行,方法在哪個對象的環(huán)境下執(zhí)行,該方法內(nèi)的$this 就表示哪個對象。
繼承和重寫 繼承
執(zhí)行環(huán)境向下環(huán)境.一個對象擁有或者使用另一個對象的成員信息,稱之為這個對象繼承自另一個對象。
PHP中,通過在類上,使用特殊的操作達(dá)到目的。
繼承是對象的概念,只不過語法上面要通過類來實(shí)現(xiàn)。通過在在定義類時,利用extends 來指明當(dāng)前類的對象 , 繼承那個類的對象。
class C { public $p_c = "value C"; } class D extends C { public $p_d = "value D"; } $d = new D(); var_dump($d->p_d); var_dump($d->p_c);繼承,指的是兩個對象之間,那么哪有這兩個對象?
class C { public $p_c = "value C"; } class D extends C { public $p_d = "value D"; } $d = new D(); var_dump($d instanceof D); // true var_dump($d instanceof C); // true相關(guān)概念
class D extends C {}
D 類對象 繼承自 C 類對象
父類:被繼承的類,C類
子類:需要繼承的類,D類功能上:
基類:C類是D類的基類
擴(kuò)展類:D類是C類的擴(kuò)展類繼承概念體現(xiàn)在對象上,語法體現(xiàn)在類上。
語法意義就是,面向?qū)ο笳Z法中的,代碼的重用PHP是單繼承
單繼承,一個類只能繼承自另一個類,不能同時繼承多個類。但是一個類可以被多個類繼承。繼承的目的:
重寫override
在于擴(kuò)展,或使用某個類已經(jīng)存在的操作和數(shù)據(jù)。
繼承,在編程上,可以是理解成OOP代碼的共用。只有發(fā)生在繼承上,才會出現(xiàn),是一個現(xiàn)象。
如果子類,與父類,出現(xiàn)同名的成員(屬性方法),則在實(shí)例化子類對象時,只會得到子類中定義的成員,稱之為重寫。成員沖突
繼承時,如果發(fā)生成員沖突,PHP的處理方式,為重寫。就是子類同名成員會覆蓋父類的同名成員。不能看到父類的成員。class P { public $name = "p"; public function sayNmae () { echo "parent::name", $this->name; } } class C extends P { public $name = "C"; public function sayName () { echo "self::name",$this->name; } } $obj = new C(); echo $obj->name; // C echo "
"; $obj->sayName(); // self::nameC某些情況下,重寫時一定發(fā)生的,例如構(gòu)造等。
如果需要,強(qiáng)制執(zhí)行被重寫的父類方法,可以顯式的使用父類來調(diào)用相應(yīng)的父類方法即可。public function __construct () { P::__construct(); }可以使用一個關(guān)鍵字,在類內(nèi),代替當(dāng)前類的父類。
parent 關(guān)鍵字,代替父類。
一旦重寫,父類代碼就不會在執(zhí)行了。P::__construct(); parent::__construct();如果說父類的構(gòu)造需要相應(yīng)的參數(shù),則需要將再調(diào)用時,將父類的構(gòu)造方法需要的參數(shù),也傳遞到方法內(nèi)。
class GoodsBook extends Goods { public $page; public function __construct ( $name, $price, $pages ) { parent::__constuct($name, $price); $this->pages = $pages; } }一般2到3層的繼承,就基本上可以
instanceof 操作符
用于判斷一個對象是否是某個類的實(shí)例
$this的確定只有在使用對象調(diào)用非靜態(tài)方法時,才可以使用$this!
哪個對象調(diào)用方法,方法內(nèi)$this就是那個對象。
對象環(huán)境,是可以向下傳遞。
如果當(dāng)前方法內(nèi),已經(jīng)確定了對象環(huán)境。在該方法內(nèi),如果出現(xiàn)了靜態(tài)調(diào)用非靜態(tài)方法,此時當(dāng)前的對象環(huán)境,會傳遞到靜態(tài)方法調(diào)用的非靜態(tài)方法中。
class A { public function in_a () { var_dump($this); } } class B { public function in_b () { var_dump($this); // B 實(shí)例化對象 echo "PHP連接MySql 設(shè)置屬性和連接方法
"; A::in_a(); // B 實(shí)例化對象 } } $obj = new B(); $obj->in_b();構(gòu)造方法內(nèi),使用數(shù)組作為參數(shù),如果參數(shù)過多,便于管理。
利用參數(shù),為對象屬性進(jìn)行賦值
常見的,在實(shí)際操作中:為屬性設(shè)置默認(rèn)值。如果用戶在實(shí)例化時,傳遞了屬性參數(shù),則使用用戶傳遞的,否則使用默認(rèn)值。// $params Array public function __construct ( $params ) { $this->host = isset($params["host"]) ? $params["host"] : "127.0.0.1"; $this->port = isset($params["port"]) ? $params["port"] : "3306"; $this->user = isset($params["user"]) ? $params["user"] : "root"; $this->pass = isset($params["pass"]) ? $params["pass"] : ""; $this->charset = isset($params["charset"]) ? $params["charset"] : "utf8"; $this->dbname = isset($params["dbname"]) ? $params["dbname"] : ""; $this->prefix = isset($params["prefix"]) ? $params["prefix"] : ""; }連接應(yīng)該在構(gòu)造方法內(nèi)完成
要求,一個功能,盡量使用一個方法獨(dú)立完成,一個大的功能,是由多個小功能組合起來。// 連接數(shù)據(jù)庫 public function connect () { mysql_connect("$this->host:$this->port",$this->user,$this->pass); }為當(dāng)前的功能類,增加一個屬性,保存這個鏈接資源
// 運(yùn)行時生成的信息 public $link;在連接成功后,為屬性賦值
連接失敗,給出提示public function connect () { if ( $link = mysql_connect("$this->host:$this->port",$this->user,$this->pass) ) { $this->link = $link; } else { echo "連接失敗"; exit; } }設(shè)置字符集,提取執(zhí)行SQL設(shè)置字符集
// 設(shè)置字符集 public function setCharset () { $query = "set names $this->charset"; if ( mysql_query($query) ) { // 成功 } else { // 失敗 echo "字符串設(shè)置失敗"; exit; } }執(zhí)行sql語句
// 執(zhí)行SQL語句 public function query ( $query ) { if ( $reslut = mysql_query($query,$this->link) ) { // 執(zhí)行成功 return $reslut; } else { // 執(zhí)行錯誤 ,給出提示 echo "SQL執(zhí)行錯誤,錯誤信息:
"; echo "出錯的SQL為:", $query ,"
link), "
"; echo "錯誤的信息為:", mysql_error($this->link), "
"; // 簡單錯誤處理,一旦出錯,直接停止掉腳本執(zhí)行 die; // 如果在完整的處理過程中, 出錯應(yīng)該余下代碼繼續(xù)執(zhí)行 // 需要判斷是否執(zhí)行成功 ,返回false return false; } }
"127.0.0.1","port","3306","user",); public function __construct( $params ){ //對屬性初始化 //如果配置項(xiàng)選項(xiàng)存在,則使用用戶的,否則使用默認(rèn)的。 $this->host = isset( $params["host"] ) ? $params["host"] : "127.0.0.1" ; $this->port = isset( $params["port"] ) ? $params["port"] : "3306"; $this->user = isset( $params["user"] ) ? $params["user"] : "root"; $this->pass = isset( $params["pass"] ) ? $params["pass"] : ""; $this->charset = isset( $params["charset"] ) ? $params["charset"] : "utf8"; $this->dbname = isset( $params["dbname"] ) ? $params["dbname"] : ""; $this->prefix = isset( $params["prefix"] ) ? $params["prefix"] : ""; //連接 $this->connect(); //設(shè)置字符集 $this->setCharset(); //選擇默認(rèn)數(shù)據(jù)庫 $this->selectDB(); } // 連接數(shù)據(jù)庫服務(wù)器 public function connect(){ if( $link = mysql_connect("$this->host:$this->port",$this->user,$this->pass) ){ //連接成功 $this->link = $link; } else { //連接失敗 echo "連接失敗 !"; exit; } } // 設(shè)置字符集 public function setCharset(){ $query = "set names $this->charset"; $this->query($query); } // 選擇默認(rèn)數(shù)據(jù)庫 public function selectDB(){ $query = "use $this->dbname"; $this->query($query); } // 執(zhí)行SQL語句 // @param $query string 需要執(zhí)行的SQL語句. // @return mixed 成功返回資源結(jié)果集或者true. 失敗返回false. public function query( $query ){ if( $result = mysql_query($query,$this->link) ){ //執(zhí)行成功 return $result; } else { //執(zhí)行失敗 //給出錯誤提示 echo "SQL執(zhí)行出錯,錯誤信息如下:訪問控制說明 訪問修飾限定符
"; echo "出錯的SQL語句為:",$query,"
"; echo "錯誤的代碼為:",mysql_errno($this->link),"
"; echo "錯誤的信息為:",mysql_error($this->link),"
"; //簡單錯誤處理,一旦出錯,直接停止腳本執(zhí)行. die; //如果再完整的處理過程中,出錯應(yīng)該余下的代碼繼續(xù)執(zhí)行。 //需要判斷是否執(zhí)行成功,返回false. // return false; } } } $db = new MYSQLDB( array("host"=>"127.0.0.1","port"=>3306,"user"=>"root","pass"=>"") ); var_dump($db); ?>public , protacted, private
用于描述,一個成員(屬性,方法)在哪里才能被訪問的。php5中,要求所有的成員(屬性和方法)都應(yīng)該受訪問修飾的控制,聲明時,前面都應(yīng)該存在訪問修飾限定符
存在例外,為了兼容.
在聲明屬性時,可以使用特殊的 var 關(guān)鍵字.相當(dāng)于使用public來聲明.
class Student { var $stu_id; }方法中,聲明時,可以省略訪問修飾限定符.相當(dāng)于public.
class Student { function sayCount () {} }public ,公共的,成員在類內(nèi),繼承鏈上類內(nèi),和類外都可以訪問到(任何地方)
protacted , 保護(hù)的,就是類內(nèi)和繼承鏈上的類內(nèi) 都可以訪問.
private , 私有的, 類內(nèi).PHP是采用類的概念,進(jìn)行成員的限制訪問的。
PHP將訪問的代碼,分成三大區(qū)域:類內(nèi),類外,繼承鏈上的類內(nèi)。
類內(nèi): 定義該成員所在類的內(nèi)部.
繼承鏈上的類內(nèi)
類外類外訪問:只有公共可以訪問
類內(nèi)訪問:類中所定義的方法內(nèi)
所有的限定都可以繼承鏈上的類內(nèi):
保護(hù)的和公共的可以被訪問,而私有的不可以被訪問.根據(jù):成員在哪里定義 與 成員在哪里訪問 來決定 類內(nèi) , 類外 還是 繼承鏈上的類內(nèi)。
注意
受保護(hù),繼承鏈上的類內(nèi)
父類內(nèi)定義,子類內(nèi)訪問. 反過來,子類內(nèi)定義父類內(nèi)可以訪問.私有成員的問題
出現(xiàn)在 私有屬性 的重寫上
PHP會記錄所有的私有屬性,同時會記錄私有屬性所在的類,在不同類內(nèi)訪問不同的私有屬性時是不同的。而, 公共的和 受保護(hù)的, 則只會記錄一次,明顯的被重寫了;
寫繼承的時候,如果是有屬性被重寫了,要注意到,當(dāng)前所訪問的私有屬性是哪一個私有屬性.私有成員不能被重寫。意味著,在相應(yīng)的私有屬性定義在類中,才能訪問到相應(yīng)的私有屬性。
建議是:如果需要通過繼承,就使用保護(hù)的,少用私有的。在沒有繼承時,盡量使用私有的。
重寫的問題,要先明確訪問的究竟是哪里所定義的。
在重寫時,如果重寫成員的訪問級別不一致。子類的級別比父類的級別,相等或者弱,可以。強(qiáng),不行。
封裝怎么使用訪問修飾,如何選擇
原則:盡量提高,類對其成員的控制能力. 能用private,盡量使用private,能用protected就不用public.
一個原則,盡量體現(xiàn)封裝性。封裝性,指的是,盡量隱藏內(nèi)部實(shí)現(xiàn),而僅僅開發(fā)外部操作接口!
語法上,就是,將不需要外部使用的屬性,方法,都私有化(保護(hù)化),而僅僅留下一些必要的公共方法!選擇訪問修飾限定符,體現(xiàn)oop思想的封裝性的特點(diǎn).
封裝性:隱藏對象的內(nèi)部實(shí)現(xiàn)細(xì)節(jié),只提供外部操作方法。
對象的外部操作方法,稱之為對象的接口(interface). 接口在語法上,就是一些公共的方法.
封裝:只有操作接口可以被看到,內(nèi)部實(shí)現(xiàn)都被隱藏.經(jīng)典的:幾乎所有的屬性和大部分的方法都是私有(如果有繼承的話,會有受保護(hù)).只有一些供外部調(diào)用者使用的方法,是公共的.
類: 繼承和實(shí)例化
類: 調(diào)用其靜態(tài)成員
類: 作為其他類的基礎(chǔ)類,被繼承
兩大功能:實(shí)例化對象, 基礎(chǔ)類被繼承抽象類: 只能被繼承,不能被實(shí)例化對象
final類
final類: 只能被實(shí)例化,不能被繼承該類,只能被實(shí)例化對象不能用于被繼承。
設(shè)計(jì)時,該類不能再擴(kuò)展,就應(yīng)該通過語法,final限制,其它用戶擴(kuò)展該類.
最終,在繼承鏈條上, 最末的一個類,其下不能再出現(xiàn)子類,意味著不能被繼承。定義
在 class 前 加 final關(guān)鍵字,即可.final class GoodsBook extends Goods {}如果繼承該類,會報(bào)錯
因此,final 類的作用,是在語法上,人為的限定哪些類不能被繼承.
final 關(guān)鍵字的另一個用法, 用于限制方法,在所屬類,被繼承時,該方法不能被重寫.
// 所有商品輸出價(jià)格方式一致 final public function sayPrice() { echo "¥",$this->shop_price; }抽象類abstract有一種類,只能被繼承,不能被實(shí)例化對象。原因就是這個類的定義不完整. (有了一半的藏寶圖,需要找到其它的藏寶圖,補(bǔ)充完整) 為什么會不完整? 因?yàn)镻HP支持定義一種,只有方法的聲明部分,而沒有方法的實(shí)現(xiàn)部分的不完整方法。(類所包含的元素,不完整,可以不完整的是方法)。
如果某個類,包含了這種不完整的方法,就不是一個完整的類,就不能實(shí)例化對象!
不完整的類, 稱之為 抽象類. abstract class
所包含的不完整的方法,稱之為:抽象方法. abstract method
定義
包含了抽象方法的類,就是抽象類語法
定義抽象方法,利用一個叫 abstruct 的關(guān)鍵字,告知PHP某個方法時一個抽象方法,沒有方法體abstract public funciton sayName(); // 要注意分號定義一個抽象類
如果一個類包含了抽象方法,也就是抽象類,因此也需要使用 abstruct 關(guān)鍵字聲明.沒有實(shí)例化的能力
實(shí)例化報(bào)錯
只有被繼承的能力
如果繼承某個抽象類的類是非抽象類的話,就一定要將不完整的抽象方法實(shí)現(xiàn)。否則該類也應(yīng)該是一個抽象類.抽象類的具體功能
1:限制子類的結(jié)構(gòu)由于抽象類,只能被繼承,而且如果其子類不是一個抽象類的話,要求必須實(shí)現(xiàn)抽象類所定義的抽象方法,因此抽象類的功能也可以理解成,用于限制其子類(擴(kuò)展類)的結(jié)構(gòu).
就可以保證,同一系列的處理類,所擁有的結(jié)構(gòu)是一致的。將來可以實(shí)現(xiàn)無縫對接,任意切換(熱插拔) 。
2:可以限制
方法名,參數(shù)個數(shù).
訪問修飾控制.
擴(kuò)展類(子類)的權(quán)限限制,弱于抽象類抽象類功能
接口 interface
在可以為子類(擴(kuò)展類)提供共用操作的同時,限制子類(擴(kuò)展類)所擁有的方法的結(jié)構(gòu).
犧牲掉了實(shí)例化對象的功能.一個對象的封裝,分為兩大部分
內(nèi)部實(shí)現(xiàn)
就是操作接口
PHP中,可以規(guī)定,一個對象應(yīng)該具有哪些公共的外部操作,使用interface來規(guī)定
公共的方法就是接口
用于規(guī)定一個對象應(yīng)該擁有哪些公共的操作方法(接口),這個東西也叫接口(公共操作方法的集合).
接口(interface 結(jié)構(gòu),公共方法的集合)公共方法(接口方法)
定義:用于限定某個對象所必須擁有的公共操作方法的一種結(jié)構(gòu),稱之為接口(interface).
就是用于限制公共方法。語法:
定義這個接口結(jié)構(gòu),使用interface 關(guān)鍵字.接口定義的都是公共的方法interface 接口名 { 公共操作方法列表 } interfece I_Goods { public function sayName(); public function sayPrice(); }注意:
接口方法,必須都是公共的
接口內(nèi)只能有公共方法,不能存在成員變量屬性interfece I_Goods { public $goods_name; //報(bào)錯 public function sayName(); public function sayPrice(); }接口內(nèi),只能含有未被實(shí)現(xiàn)的方法,也叫抽象方法,但是不用abstract關(guān)鍵字().
如果是一個完整方法,會報(bào)錯。使用接口
限制對象的必要的公共操作
類實(shí)現(xiàn)接口 (實(shí)現(xiàn)--把你想做的事完成). 利用關(guān)鍵字, implements;class Goods implements I_Goods {}這樣,實(shí)現(xiàn)該接口的類,必須實(shí)現(xiàn)接口內(nèi)所有的抽象方法。而且可以肯定,該方法一定是公共的外部操作方法
// 定義接口 interface I_Goods { public function sayName(); public function sayPrice(); } // 實(shí)現(xiàn)接口 class Goods implements I_Goods { public $goods_name; public $shop_price; public function __construct ( $name, $price ) { $this->goods_name = $name; $this->shop_price = $price; } public function sayName () { echo $this->goods_name; } public function sayPrice () { } } $goods = new Goods("php", 234); $goods->sayName(); $goods->sayPrice();類似于抽象類,比較與接口的區(qū)別:
抽象類與普通類之間是繼承關(guān)系
普通類繼承抽象了,第一可以得到抽象類中的已有的常規(guī)成員,第二才需要實(shí)現(xiàn)抽象方法(也不一定是public)接口與普通類之間是實(shí)現(xiàn)關(guān)系
普通類實(shí)現(xiàn)了接口,只能將其沒有實(shí)現(xiàn)的公共方法實(shí)現(xiàn)接口只用于定義 公共的方法。 而抽象類,什么都可以有。
多實(shí)現(xiàn)
上面的功能,理論上講,可以通過抽象類完成。 但是抽象類,不專業(yè)
接口專業(yè)體現(xiàn)在實(shí)現(xiàn)上,因?yàn)镻HP支持多實(shí)現(xiàn),而僅支持單繼承.class Goods implements I_Goods, I_Shop { }繼承和實(shí)現(xiàn)區(qū)別
繼承:體現(xiàn)的是將別的對象已經(jīng)存在的東西,拿來自己用
實(shí)現(xiàn):將某個地方的規(guī)定,自己來完成接口之間,也可以繼承
interface I_Shop extend I_Goods { public function saySafe(); }抽象類 pk 接口
繼承 pk 實(shí)現(xiàn)PHP對接口的支持,可以定義常量
interface I_Shop extend I_Goods { const PAI = 3.14; }通過類去訪問
class Goods implements I_Shop {}
echo Goods::PAI;辨別
繼承應(yīng)用 表操作模型
接口是不是類 ?
接口不是類,接口就是獨(dú)立的一種結(jié)構(gòu),適用于限制類的結(jié)構(gòu)。但是可以理解成"接口類似于一個所有的方法都是公共的抽象方法,而且沒有其它成員的抽象類",并不是一個概念。
class_exists(); 判斷一個類是否存在?項(xiàng)目中操作數(shù)據(jù)庫的典型模式: 數(shù)據(jù)操作模型(model).
常見的操作
PHP項(xiàng)目中,由于不同的數(shù)據(jù)實(shí)體對應(yīng)的業(yè)務(wù)邏輯是不同的,通常的操作數(shù)據(jù)的方法:為每張表創(chuàng)建一個操作對象class BaseTable {} class GoodsTable extends BaseTable {} class CrtegoryTable extends BaseTable {}如果兩個類有具體的關(guān)系,使用繼承.
聚合如果是多個類需要使用另一個類,所提供的功能,還有一種方式,稱之為聚合.
class MySQLDB { public function query () { } } class BrandTable { public $db; public function __construct () { $this->db = new MysqlDB(); $this->db->query(); } } $brand = new BarndTable(); $brand->db;如果,BrandTbale 類 對象,需要使用MySQLDB類對象的相應(yīng)功能,可以BrandTable對象內(nèi),增加一個屬性保存MySQLDB類對象。打到 BarndTable使用MySQLDB 對象的功能目的
這種方式,稱之為 對象的聚合。既然聚合 和 繼承 都可以達(dá)到 共用一個類功能的目的,使用的標(biāo)準(zhǔn)
如果說兩個類之間存在邏輯關(guān)系上的必然聯(lián)系,就建議使用繼承。
反之,如果是邏輯上,一個對象使用另一個對象,此時應(yīng)該使用對象間的聚合。優(yōu)劣性
自動加載機(jī)制
使用繼承,可以增加類之間的聯(lián)系,增加關(guān)聯(lián)性。
而使用聚合,可以降低類之間的關(guān)聯(lián)性,可以降低耦合性!保存類的方法:
將類的定義代碼,放置在一個獨(dú)立的文件中. 如果需要該類,則直接調(diào)用.為了識別,某個類定義文件,常見的,類定義文件的命名方式為:
類名.class.php使用時引入:
require("./MySQLDB.php");思考:
如果項(xiàng)目中,多處使用OOP,導(dǎo)致整個項(xiàng)目中,出現(xiàn)多個 xxx.class.php 文件,每當(dāng)需要都需要引入 ?使用自動加載,按需引入類文件
需要解決的問題:
1,什么時候需要類?
實(shí)例化時,靜態(tài)調(diào)用時,一個類被繼承時如果使用其子類時。
2,在需要時,應(yīng)該主動require 系列的代碼, 才可能加載成功,如何做到需要自動執(zhí)行某段代碼?
3,需要的是類,而載入的是文件,需要解決如何通過 類 來確定 類文件的所在文件.PHP解決了前2個問題,需要解決第三個問題。
PHP提供了一個機(jī)制(功能),可以在需要某個類,但是沒有載入這個定義類時.會自動調(diào)用某個函數(shù)。并同時將當(dāng)前所需要的類名,作為參數(shù)傳遞到這個自動調(diào)用的函數(shù)內(nèi)。
PHP提供一個時機(jī),完成自動加載。
這個函數(shù)默認(rèn)不存在,需要用戶自己定義。 函數(shù)名為 __autoload();function __autolaod ( $class_name ) { var_dump($class_name); require $class_name.".class.php"; }一旦函數(shù)存在,在特定情況(需要類但是沒有找到),則PHP內(nèi)部會自動調(diào)用__autoload().執(zhí)行在函數(shù)體定義的函數(shù),從而完成加載類所在的文件。
分工:
用戶腳本:定義函數(shù),接收需要的類名作為參數(shù),函數(shù)需要實(shí)現(xiàn)通過類名找到類所在的文件,將其載入即可!
PHP核心(Zend Engine):判斷是否需要類,并且判斷該類是否已經(jīng)載入了,如果需要但是沒有載入,則嘗試調(diào)用用戶定義的__autoload()函數(shù),并將需要的類名傳遞即可!__autoload 函數(shù)名得到是類名
而載入的是類文件定義的文件。
因此,自動加載機(jī)制的前提:必須要能夠通過類名,推導(dǎo)出,類所在的文件才可以。(定義類文件時,要有規(guī)律)注意:
對象序列化
PHP提供了加載代碼的執(zhí)行時機(jī)。用戶腳本,需要完成加載代碼,其中核心任務(wù)是,通過所得到的類名,找到類定義所在的文件。序列化,反序列化(串行化,反串行化)
數(shù)據(jù)持久化
在數(shù)據(jù)保存,面臨一個問題:數(shù)據(jù)格式。PHP的數(shù)據(jù)有八種類型之多,文件只能存儲字符串。
一旦數(shù)據(jù)類型不是字符串類型。就會導(dǎo)致數(shù)據(jù)不能原樣保存,不能取得原始數(shù)據(jù)。
如何解決
任何形式的數(shù)據(jù),都可以存儲到文件中,并且,在取出來時,原樣得到數(shù)據(jù)。
在保存,與讀取時,對數(shù)據(jù)進(jìn)行轉(zhuǎn)換與反轉(zhuǎn)換。序列化
serialize();
原始數(shù)據(jù)轉(zhuǎn)成能夠記錄的原始數(shù)據(jù)信息的字符串反序列化
unserialize();
通過序列化的字符串結(jié)果,將原始數(shù)據(jù)還原!只有在涉及到,數(shù)據(jù)需要被存儲,或者 傳輸時, 需要對數(shù)據(jù)進(jìn)行序列化。
注意的數(shù)據(jù)類型都可以被序列化與反序列外。資源是例外!
對象的序列化與反序列化
在對象被反序列化時,需要找到當(dāng)前對象所屬的類才可以被完美的反序列化,如果不能找到屬于的類,那么會變成php內(nèi)置類:__PHP_Incompleta_Class(不完整類)的一個對象.
因此,只要在反序列話之前,將類載入即可。反序列化,也會觸發(fā)自動加載機(jī)制。
在序列化時,可以自定義需要序列化的屬性名單!
通過對象的特殊的方法 __sleep();
該方法會在對象被序列化時,自動調(diào)用,不需要參數(shù),返回一個數(shù)組,每個元素,表示一個屬性名,數(shù)組內(nèi)存在的屬性名,就會被序列化。反之則不會被序列化。// 在序列化時被調(diào)用 // 用于負(fù)責(zé)指明那些屬性需要被序列化 // @return array public function __sleep () { return array("host", "port", "user", "pass", "charset", "dbname"); }在反序列化時,可以自動再次執(zhí)行某些代碼,從而完成某些資源的初始化!
通過 對象方法:__wakeup()方法
會在 對象被反序列過程中自動調(diào)用,所負(fù)責(zé)的功能,執(zhí)行反序列話(醒來之后)的初始化工作!// 在反序列化時調(diào)用 // 用于 對對象的屬性進(jìn)行初始化 public function __wakeup () { // 連接數(shù)據(jù)庫 $this->connect(); // 設(shè)置字符集 $this->setCharset(); // 設(shè)置默認(rèn)數(shù)據(jù)庫 $this->selectDB(); }PHP 自動調(diào)用, 用戶腳本只需要定義。在特定的功能調(diào)用特定的方法。稱之為:魔術(shù)方法。
單例模式單例,單個實(shí)例。設(shè)計(jì)模式的一種,通過一種語法的設(shè)計(jì),保證類(對象)上具有某些特征,這樣的一種語法實(shí)現(xiàn),就可以稱之為設(shè)計(jì)模式。
其中,設(shè)計(jì)可以保證一個類,有且只有一個對象,這種設(shè)計(jì)模式就稱之為單例模式。單例模式的作用,單例的設(shè)計(jì),是適用于使用一個對象可以完成所有業(yè)務(wù)邏輯的類
典型的實(shí)現(xiàn),在類上,做限制:三私一公。
某個類只要實(shí)例化一次就可以完成所有的業(yè)務(wù)邏輯!
但是實(shí)例化多次也可以。顯然,應(yīng)該保證對象被實(shí)例化一次,從而節(jié)約資源空間!
MySQLDB類,如何設(shè)計(jì),從而達(dá)到保證該類 有且只有一個對象.
原因:使用者,可以無限次的去實(shí)例化 這個類。三私一公
1:限制,用戶無限制執(zhí)行new
在實(shí)例化的過程中,需要執(zhí)行構(gòu)造方法,如果執(zhí)行不成功,那么實(shí)例化過程失敗。因此,將構(gòu)造方法,私有化(保護(hù)化),可以保證在類外進(jìn)行實(shí)例化的工作都會失敗。class MySQLDB { private function __construct () { } }2,類,不能實(shí)例化了,不能再類外實(shí)例化,可以在類內(nèi)實(shí)例化,類內(nèi)執(zhí)行new操作。
因此:在類中,增加一個公共的靜態(tài)的方法,在方法內(nèi),執(zhí)行new實(shí)例化類對象。
class MySQLDB { // 私有化構(gòu)造函數(shù) private function __construct () { } // 執(zhí)行new public static function getInstance () { return new MySQLDB(); } } $db1 = MySQLDB::getInstance(); $db2 = MySQLDB::getInstance(); var_dump($db1, $db2);3,可以無限制的調(diào)用getInstance得到任意多個對象!但是此時得到對象都需要經(jīng)過 getInstance,可以在getInstance內(nèi),增加限制,使用戶得到對象的改變!
在實(shí)例化好對象后,將對象存起來,下次再執(zhí)行時,判斷是否已經(jīng)有保存的,有了,直接返回已經(jīng)存在的,沒有,實(shí)例化后,保存起來,再返回!
增加一個私有的靜態(tài)屬性,在 getinstance內(nèi)做判斷class MySQLDB { // 判斷是否實(shí)例化過 public static $getinstance; // 私有化構(gòu)造函數(shù) private function __construct () { } // 執(zhí)行new public static function getInstance () { // 沒有實(shí)例化 if ( !(self::$getinstance instanceof self) ) { self::$getinstance = new self; } return self::$getinstance; } }4:還可以通過克隆來得到新對象
需要私有化__clone()方法// 私有化 __clone 方法 private function __clone () { }注意:單例模式傳參問題
在項(xiàng)目的設(shè)計(jì)層面解決單例的問題
增加一個實(shí)例化的方法(函數(shù))
作用:用戶如果想要得到單例對象,就通過調(diào)用該函數(shù)完成!function getInstace ( $class_name ) { static $objects = array(); if ( !isset($objects[$class_name]) ) { $objects[$class_name] = new $class_name; } return $objects[$class_name]; }優(yōu)點(diǎn):靈活,可以針對多個類同時實(shí)現(xiàn)單例,而且,類還可以回歸到非單例的效果。
重載overload屬性重載 __set() __get()
傳統(tǒng)意義的重載,一個方法的多種狀態(tài),通常使用,參數(shù)類型或者參數(shù)個數(shù)進(jìn)行區(qū)分,決定當(dāng)前使用那個函數(shù)。
PHP不支持同名方法。
PHP的重載:指的是對不可訪問的成員的操作。
不可訪問的成員: 指的是 不存在 , 或者是,由于訪問修飾控制訪問不到的。// PHP允許為對象增加類中沒有定義的屬性 class Student { public $stu_name; private $stu_id; } $stu = new Student(); var_dump($stu); echo "
"; $stu->stu_gender = "male"; var_dump($stu);
// PHP對屬性除了增加,還支持刪除 class Student { public $stu_name; private $stu_id; } $stu = new Student(); $stu->stu_gender = "male"; unset($stu->stu_name); var_dump($stu);對類后續(xù)進(jìn)行操作,用戶可以操作對象任意的修改對象的結(jié)構(gòu)。
PHP如何處理上面的情況,稱之為重載(屬性的重新加載,成員的重新加載).重載:對成員的重新加載
成員分為:屬性和方法,因此,php支持屬性重載 和 方法重載.
屬性重載PHP對,不可訪問的屬性進(jìn)行操作處理方法,稱之為屬性重載
PHP需要通過支持 魔術(shù)方法完成。
PHP在處理重載屬性時,支持使用4個魔術(shù)方法,完成處理屬性重載的情況.__set()
當(dāng)為不可訪問的屬性賦值時,會被自動調(diào)用
會得到兩個參數(shù),當(dāng)前操作的屬性名,和屬性值!// $p_name string 屬性名 // $p_value mixed 屬性值 public function __set ( $p_name, $p_value ) { // 實(shí)現(xiàn), 處理情況 return ; }典型的,__set()的作用, 用于嚴(yán)格控制對象結(jié)構(gòu),和批量處理可以被修改的屬性。
// $p_name string 屬性名 // $p_value mixed 屬性值 public function __set ( $p_name, $p_value ) { // 實(shí)現(xiàn), 處理情況 // 不可增加任何屬性, 但是可以對 age 和 gender 做出修改 $allow_preperties = array("s_age", "s_gender"); if ( in_array($p_name, $allow_preperties) ) { $this->$p_name = $p_value; // 利用可變屬性,屬性名由變量代替 } } $s = new Student(); $s->s_name = "天機(jī)老人"; $s->s_age = 87;__get()
當(dāng)訪問不可訪問的屬性時,會被自動調(diào)用
需要的參數(shù)是:一個,為當(dāng)前操作的屬性名public function __get ( $p_name ) { // 讀取名字 性別 if ( $p_name == "s_name" || $p_name == "s_gender" ) { return $this->$p_name; // 可變屬性 } else { // 讀取年齡 if ( $this->s_gender == "male" ) { return $this->s_age; } } }__unset()
在刪除一個不可訪問的屬性時,可以自動被調(diào)用!
需要一個參數(shù) 當(dāng)前操作的屬性名。
此時就可以利用業(yè)務(wù)邏輯完成 屬性的刪除處理!public function __unset ( $p_name ) { if ( $cound ) { unset($this->$p_name); } }__isset()
在判斷一個不可訪問的屬性是否存在時,被自動調(diào)用
需要一個參數(shù),屬性名
注意,次函數(shù)需要返回true,或者false,表示屬性是否存在public function __isset ( $p_name ) { if ( $p_name == "s_gender" ) { return true; } else { return false; } }方法重載__call()
當(dāng)訪問一個不可訪問的對象方法時,會觸發(fā)__call()的魔術(shù)方法!
需要的參數(shù)時:
2個參數(shù),第一是當(dāng)前的方法名,第二是調(diào)用時使用的實(shí)參列表!public function _call ( $m_name, $m_args ) { var_dump($m_name, $m_args); } $s = new Student(); $s->sayName("zf", "php");典型應(yīng)用
1,給出友好提示
2,執(zhí)行默認(rèn)操作public function _call ( $m_name, $m_args ) { var_dump($m_name, $m_args); echo "執(zhí)行了默認(rèn)操作"; $this->default_action(); } public function default_action () { echo "這里是操作"; } $s = new Student(); $s->sayName("zf", "php");static __callStatic()
與 __call類似,當(dāng)靜態(tài)調(diào)用一個不可訪問的方法時,會自動執(zhí)行!
public static function __callStatic ( $m_name, $m_args ) { var_dump( $m_name, $m_args ); } Student::sayCount();魔術(shù)方法
magic method在特定的情況下,會被自動調(diào)用的方法,通常負(fù)責(zé)完成某塊獨(dú)立的功能的方法稱之為魔術(shù)方法!
特點(diǎn):1,需要用戶腳本定義,不定義不執(zhí)行!2,命名方式都是以__開頭__invoke()
將一個對象,當(dāng)作函數(shù)調(diào)用時,會觸發(fā)該對象的__invoke()方法,由此方法,就可以調(diào)用,沒有該方法就不能調(diào)用!
__invoke是PHP實(shí)現(xiàn)匿名函數(shù) 不可或缺的部分!
也可以傳遞參數(shù),為對象傳遞參數(shù),就是為invoke魔術(shù)方法傳遞參數(shù)!
Closure 類的對象(匿名函數(shù),閉包函數(shù)) 可以當(dāng)作函數(shù)調(diào)用,為什么我們自己定義的對象不可以當(dāng)做函數(shù)調(diào)用? 內(nèi)置的Closure 類中有 __invoke();方法.
在將一個對象當(dāng)做函數(shù)調(diào)用時, 會觸發(fā)該對象的 __invoke 方法, 如果方法不存在,對象不能當(dāng)做函數(shù)調(diào)用。反之 如果需要調(diào)用這個對象, 則可以為該對象增加 __invoke 方法使之執(zhí)行.
調(diào)用對象,其實(shí)就是調(diào)用該方法,可以接受參數(shù)!普通方法一樣處理即可.
魔術(shù)方法,只會負(fù)責(zé)某個特定的功能。當(dāng)某個特別的情況發(fā)生時,才會調(diào)用相應(yīng)的魔術(shù)方法。
魔術(shù)方法可以沒有, 一旦有的話就會被調(diào)用.__toString()
轉(zhuǎn)換到字符串的意思!
當(dāng)將對象當(dāng)作字符串使用時,會自動調(diào)用該對象的魔術(shù)方法!存在toString 魔術(shù)方法,即可以完成轉(zhuǎn)換。
靜態(tài)延遲綁定
toString的返回值,就是轉(zhuǎn)換的結(jié)果,一般轉(zhuǎn)換對象的標(biāo)志性的屬性即可!$this永遠(yuǎn)代表所在類的對象?
不是
$this的值取決于$this所在方法的執(zhí)行對象環(huán)境.self用于代表所在類么?
是,永遠(yuǎn)代表所在類的對象!
self 永遠(yuǎn)表示所在的類.
在那個類中被定義,就應(yīng)該表示那個類.
因?yàn)閟elf,parent關(guān)鍵字,類的編譯階段就確定了所代表的類.class P { public static $where = "P static,
"; public static function sayWhere () { echo self::$where; } } class C extends P { public static $where = "C static"; } echo P::sayWhere(); // P static, echo C::sayWhere(); // P static,此時,應(yīng)該是表示當(dāng)前類的關(guān)鍵字,最好應(yīng)該在調(diào)用時決定最好?。╯elf不能做到)
此時,采用一個新的關(guān)鍵字,代表當(dāng)前類,與self不同,在于是 運(yùn)行時調(diào)用時決定,而不是在類編譯時就確定好了的!
使用關(guān)鍵字:staticclass P { public static $where = "P static,
"; public static function sayWhere () { echo self::$where; } public static function sayW () { echo static::$where; } } class C extends P { public static $where = "C static,"; } echo P::sayWhere(); // P static, echo C::sayWhere(); // P static, echo "
"; echo P::sayW(); // P static, echo C::sayW(); // C static,static關(guān)鍵字的功能
聲明靜態(tài)局部變量
聲明靜態(tài)成員
當(dāng)前類,運(yùn)行的當(dāng)前類類中,可以表示類的關(guān)鍵字:
反射機(jī)制
self, 所在類
static,調(diào)用類
parent, 父類常見的類和對象操作函數(shù):
instanceof,判斷對象是否是某個類的實(shí)例。 get_class(); // 返回對象的類名 class_exists(); // 判斷一個類是否存在 get_declared_classer() // 獲得當(dāng)前已經(jīng)存在的類. 包括預(yù)定義和用戶自定義的。 method_exists(); property_exists();相應(yīng)的魔術(shù)常量
__CLASS__ , 當(dāng)前類名
__METHOD__, 當(dāng)前方法名get_class_methods(); // 得到類的方法
get_class_vars(); // 得到類的屬性
可以得到類內(nèi)的方法和屬性。
但是,得到的信息較少,只有名字,而且受到訪問修飾符的限制。
如何才能夠詳細(xì)精確到類中的結(jié)構(gòu)?
使用到反射機(jī)制PHP提供的,用于獲得某個類,或者某種結(jié)構(gòu)(類,函數(shù),方法,屬性,參數(shù),擴(kuò)展....);
需要使用反射機(jī)制,反射機(jī)制時利用OOP的語法實(shí)現(xiàn)了。
反射機(jī)制提供了很多類,針對不同的結(jié)構(gòu),會使用到不同的反射類對象。
reflection: 反射類. 可以通過對象反過來獲得對象的相關(guān)信息.如果需要知道某個類的結(jié)構(gòu),就應(yīng)該使用refletionClass
存在一個靜態(tài)方法,refletionClass::export() 可以導(dǎo)出一個類的結(jié)構(gòu)報(bào)告反射機(jī)制可以獲得目標(biāo)結(jié)構(gòu)的內(nèi)部結(jié)構(gòu)。
并同時可以驅(qū)動目標(biāo)結(jié)構(gòu)運(yùn)行起來.(代理執(zhí)行);name, "類型約束
"; } public function tan($c1, $c2) { echo "
" . $c1 . " ". $c2; } } $p = new Persion(); // $p->say(); // 利用反射對象調(diào)用方法 $method = new ReflectionMethod("Persion", "say"); // 反射方法對象 $method->invoke($p); $method2 = new ReflectionMethod("Persion", "tan"); //參數(shù)的反射方法 $method2->invokeArgs($p, array("pink", "red")); ?>約束函數(shù),或者方法類參數(shù)的類型,只能是某個類的對象。
PHP是弱類型,變量可以存儲任意類型的數(shù)據(jù)
函數(shù),方法的參數(shù)也是可以接受任意類型但是參數(shù),可以被規(guī)定為,某個類的固定對象,在參數(shù)前增加類名即可。
function sayName ( Student $o ) { echo $o->stu_name; } sayName("php");支持類名,和數(shù)組。其它數(shù)據(jù)類型不支持。
function sayName ( Array $arr ) { }對象的遍歷對象是一個集合數(shù)據(jù)類型
foreach遍歷
遍歷對象,是依次獲得對象擁有的屬性的信息(注意,訪問修飾符的限制)class Student { public $stu_name; public $stu_age; public $stu_gender; } $obj = new Student(); $obj->stu_name = "李尋歡"; $obj->stu_age = 30; $obj->stu_gender = "male"; foreach ( $obj as $val => $key ) { var_dump($val,$key); echo "
"; }自定義遍歷,iterator
iterator迭代器接口Iterator接口,PHP預(yù)定義完成。
實(shí)現(xiàn)Iterator接口// 類實(shí)現(xiàn)Iterator 接口 class Team implements Iterator { public function rewind () { reset($this->stu_infos); } public function valid () { return key($this->stu_infos) !== null; } public function current () { return current($this->stu_infos); } public function key () { return key($this->stu_infos); } public function next () { next($this->stu_infos); } }魔術(shù)常量
__CLASS__:當(dāng)前類名。注意:可以new self 不可以 new __CLASS__
__METHOD__,當(dāng)前方法名。區(qū)別__FUNCTION__
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/21756.html
摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
閱讀 3542·2021-11-25 09:43
閱讀 2766·2021-09-22 15:54
閱讀 653·2019-08-30 15:55
閱讀 1035·2019-08-30 15:55
閱讀 2078·2019-08-30 15:55
閱讀 1806·2019-08-30 15:53
閱讀 3536·2019-08-30 15:52
閱讀 2108·2019-08-30 12:55