PHP面向?qū)ο?/h3>
面向過程編程:
其基本特征是:
將要完成的任務(wù),分割為若干個步驟:
第1步:做什么喻粹。。厂抽。
第2步:做什么。暗甥。坎怪。
.......
最后岖沛,做完了暑始,任務(wù)完成!
面向?qū)ο缶幊蹋篛OP: Object Oriented Program(面向?qū)ο缶幊蹋?其基本特征是:
將要完成的任務(wù)婴削,“分派”給不同的“對象”去做;
某對象1:會做什么牙肝。唉俗。。
某對象2:會做什么配椭。虫溜。。
........
程序一旦啟動股缸,則各個對象“各司其職”衡楞,相互配合就完成了任務(wù)。
面向?qū)ο笾械幕靖拍?類和對象
對象: 萬物皆對象敦姻;
類: 任何對象瘾境,都可以人為“規(guī)定”為某種類型(類別);
class Person{
var $name ;
var $age;
var $edu;
}
我:
姓名:羅XX镰惦,
年齡40迷守,
學(xué)歷:大學(xué);
王亮:
姓名:王亮
年齡:20旺入;
學(xué)歷:大學(xué)兑凿;
class Teacher{
var $name ;
var $age;
var $edu;
var $major; //專業(yè)
}
可見:
? 類是描述一類事物的一個總稱,是具有相同特征特性的該類事物的一個通用名字(稱呼)茵瘾;
? 對象是一個明確的具體的“物體”礼华,是某個類中的一個“實物”(相對來說,類就是一種抽象的泛稱)拗秘。對象離不開類圣絮,或者說,對象一定隸屬于某個類——有類才有對象聘殖,先有類再有對象晨雳。
屬性和方法
屬性:就是原來的“變量”,只是現(xiàn)在它“隸屬于”一個類了奸腺,即寫在一個類中餐禁,就稱為屬性;
方法:就是原來的“函數(shù)”突照,只是現(xiàn)在它“隸屬于”一個類了帮非,即寫在一個類中,就稱為方法;
注意:屬性和方法末盔,已經(jīng)不能“自由使用”了筑舅,而是都要通過這個類或這個類的對象去使用。
使用屬性陨舱,就把它當(dāng)做一個“變量”去使用就好了翠拣,只是需要該形式:對象->屬性名;
使用方法游盲,就把它當(dāng)做一個“函數(shù)”去使用就好了误墓,只是需要該形式:對象->函數(shù)名(實參列表...)
創(chuàng)建對象的幾種形式
class C1{
var $p1 = 1; //定義一個屬性;
}
形式1:
$o1 = new C1(); //通過一個類益缎,去new出一個對象
形式2:
$o2 = new $o1(); //通過一個對象谜慌,去new出一個對象——其實是new出來的是舊對象所述類的一個新對象套腹。
形式3:
$s1 = “C1”; //只是一個字符串變量而已藕溅;
$o3 = new $s1(); //這就是所謂的“可變類”——無非就是類的名字是一個變量而已。
形式4:
$o4 = new self(); //self表示“當(dāng)前類本身”拍柒,它只能出現(xiàn)在一個類的方法中令哟。
對象的傳值方式:
為什么對于對象恼琼,值傳遞和引用傳遞,這個情況下励饵,他們似乎沒有區(qū)別驳癌??役听?
這要從對象的數(shù)據(jù)的存儲方式來理解:
$o1 = new C1(); //這里創(chuàng)建一個對象o1颓鲜,其存儲結(jié)果
這里,實際上典予,變量$o1中甜滨,存儲的數(shù)據(jù)只是一個“對象編號#1”,這個對象編號瘤袖,才會去指向?qū)ο髷?shù)據(jù)new C1(); 該編號數(shù)據(jù)衣摩,我們不能控制,只是系統(tǒng)內(nèi)部的分配捂敌。
在語法上艾扮,對對象變量進行的屬性進行操作,其實就是通過該編號來指向?qū)ο蠖僮鞯摹?$o1->p1 = 2; //此時占婉,就是通過對象編號#1去修改了對象(new C1() )本身的內(nèi)部數(shù)據(jù).
echo $o2->p1; //此時相當(dāng)于取得變量$o2所包含的編號#1中所指向的對象(new C1() )的內(nèi)部數(shù)據(jù)p1
類中成員
類中成員概述
面向?qū)ο缶幊膛葑欤切枰ㄟ^“對象”去做什么事情(以完成某種任務(wù));
而:
對象總是來源于類逆济;
所以:
面向?qū)ο蟮木幊套糜瑁磺卸际菑亩x類開始磺箕;
類中成員分為3大類:
屬性:
方法:
常量:
形式上,大致如下:
class 類名 {
常量定義1抛虫;
常量定義2松靡;
.......
屬性定義1;
屬性定義2建椰;
........
方法定義1雕欺;
方法定義2;
.......
}
說明:
以上各項广凸,沒有順序問題阅茶;習(xí)慣上,其實常量放前面谅海,然后是屬性,然后是方法蹦浦;
詳細(xì)一點扭吁,就又分為:
屬性:
普通屬性;//一般屬性盲镶,實例屬性
靜態(tài)屬性侥袜;
方法:
普通方法;//一般方法溉贿,實例方法
靜態(tài)方法枫吧;
構(gòu)造方法;
析構(gòu)方法宇色;
常量:
類常量
當(dāng)在一個類中定義一個常量時九杂,該常量就稱為“類常量”——本質(zhì)其實還是常量;
定義形式:
class 類名{
const 常量名 = 常量值宣蠕;
//不可以使用define()來定義例隆!
}
使用形式:
常量的使用,是通過類名抢蚀,并使用范圍解析符(::)來取用的镀层;
類名::常量名;
普通屬性(實例屬性):
實例的單詞為:instance
實例皿曲,其實也叫做“對象”唱逢;
普通(實例)屬性,就是一個可以在該類實例化出的對象上使用的屬性屋休!
定義形式:
class 類名{
var $屬性名 = 初始值坞古;
var $屬性名; //這個屬性沒有初始值博投;
//上述的var 還可以使用public來代替绸贡,比如:
public $屬性名 = 初始值;
public $屬性名; //這個屬性沒有初始值听怕;
}
使用形式:
是通過該類的對象捧挺,來使用普通屬性(實例屬性):
$對象->屬性名;
因為尿瞭,屬性的本質(zhì)就是變量闽烙,則其就可以當(dāng)做一個變量來看待和使用,比如:
$v1 = $對象->屬性名声搁;
echo $對象->屬性名黑竞;
$v2 = $對象->屬性名 * 3 + 5; //進行計算
靜態(tài)屬性:
靜態(tài)屬性,本質(zhì)上也是“變量”疏旨,但其有一個特點就是:該變量只隸屬于“類”很魂,即:
一個類中的一個靜態(tài)屬性,就只有“一份數(shù)據(jù)”檐涝;
但:
一個類中的一個實例屬性遏匆,就可以有“多份數(shù)據(jù)”——每創(chuàng)建一個對象出來,就會有一份數(shù)據(jù)谁榜;
定義形式:
class 類名{
static $屬性名 = 初始值幅聘;
static $屬性名; //這個屬性沒有初始值窃植;
}
使用形式:
使用類名和范圍解析符(::)來對靜態(tài)屬性進行操作:
類名::$靜態(tài)屬性名帝蒿; //注意:屬性名帶$符號
對比1:
常量的使用:類名::常量名;
對比2:
實例屬性的使用:對象名->實例屬性名巷怜; //注意:屬性名不帶$符號
1葛超,實例屬性,是每個對象都可以不一樣的數(shù)據(jù)丛版,也是每個對象都“獨自擁有”的數(shù)據(jù)巩掺;
2,靜態(tài)屬性页畦,他不屬于任何一個對象胖替,而只屬于該類本身,也可以理解為為所有對象所共有的數(shù)據(jù)豫缨;
普通方法(實例方法)
一個類中定義的方法独令,可以為這個類的所有對象調(diào)用的方法。也可以理解為好芭,這個類的所有對象燃箭,都各自有自己的一個該方法;
定義形式:
class 類名{
function 方法名(形參1舍败,形參2招狸,.... ){
//方法體敬拓。。裙戏。
}
}
調(diào)用形式:
$對象名->方法名(實參1乘凸,實參2,....)累榜;
靜態(tài)方法
一個類中定義的方法营勤,只隸屬于這個類本身,而不是隸屬于這個類的對象壹罚。
定義形式:
class 類名{
static function 方法名(形參1葛作,形參2,.... ){
//方法體猖凛。赂蠢。。
}
}
調(diào)用形式:
類名::方法名(實參1辨泳,實參2客年,....);
構(gòu)造方法(__construct):
構(gòu)造方法漠吻,是一個特殊的方法:
1,名字是固定的:_ _construct司恳;
2途乃,該方法通常都不要我們自己調(diào)用,而是在new一個對象的時候會自動調(diào)用扔傅。
3耍共,該方法主要的目的是為了在new一個對象的時候,給該對象設(shè)置一些“初始值”(初始化工作)猎塞;
4试读,構(gòu)造方法的參數(shù)沒有規(guī)定,通常是根據(jù)實際的需要來定義荠耽,目的是為了對象屬性數(shù)據(jù)的初始化钩骇;
析構(gòu)方法(__destruct):
說明:
1,析構(gòu)方法是一個特殊的方法铝量,名字為固定的詞:_ _desctruct
2倘屹,析構(gòu)方法是在一個對象被“銷毀”的時候會自動被調(diào)用的方法——我們無法調(diào)用它;
3慢叨,析構(gòu)方法不能帶參數(shù)(形參)纽匙,但方法中也可以使用$this這個詞,代表“當(dāng)前對象”拍谐;
對象在哪些情況下會被銷毀烛缔?
1馏段,如果程序結(jié)束,所有變量都會被銷毀践瓷,自然院喜,變量所代表的對象也會被銷毀;
對象銷毀的順序当窗,默認(rèn)情況下够坐,跟其創(chuàng)建的順序相反;
2崖面,當(dāng)一個對象沒有任何變量“指向”它的時候元咙,即使程序還沒有結(jié)束,也會被銷毀巫员;
- 繼承
基本概念
將一個類A中的特性信息庶香,傳遞到另一個類B中,此時就稱為:
B繼承A
A派生出B
class A{
}
class B extends A{
}
幾個基本概念
? 繼承:一個類從另一個已有的類獲得其特性简识,稱為繼承赶掖。
? 派生:從一個已有的類產(chǎn)生一個新的類,稱為派生七扰。
? 父類/子類:已有類為父類奢赂,新建類為子類。父類又可以稱為“基類”颈走,上級類膳灶,子類又稱為派生類,下級類立由,
? 單繼承:一個類只能從一個上級類繼承其特性信息轧钓。PHP和大多數(shù)面向?qū)ο蟮恼Z言都是單繼承模式。C++是多繼承锐膜。
? 擴展:在子類中再來定義自己的一些新的特有的特性信息(屬性毕箍,方法和常量)。沒有擴展道盏,繼承也就沒有意義了而柑。
訪問控制修飾符
形式:
class 類名{
訪問控制修飾符 屬性或方法定義;
}
有3個訪問修飾符:
? public公共的:在所有位置都可訪問(使用)捞奕。
? protected受保護的:只能再該類內(nèi)部和該類的子類或父類中訪問(使用)牺堰。
? private私有的:只能在該類內(nèi)部訪問(使用)。
他們的作用是:用來“限制”其所修飾的成員的“可訪問性”颅围;
可訪問性:
就是在代碼中使用這樣兩種語法形式的“有效性”(合法性):
對象->實例屬性或方法伟葫;
類::靜態(tài)屬性或方法;
訪問控制修飾符院促,需要結(jié)合使用該語法形式的所在位置筏养,才能確定是否可訪問斧抱。
有3個訪問位置(范圍):
某個類的內(nèi)部:
某個類的繼承類的內(nèi)部:
某個類的外部:
1,public修飾的成員渐溶,哪里都能訪問辉浦;
2,類的內(nèi)部茎辐,可以訪問任何級別的成員宪郊;
3,public具有最寬泛的可訪問性拖陆;private具有最狹小的可訪問性弛槐;protecte則居中;
parent關(guān)鍵詞
parent表示“父母”的意思依啰,在面向?qū)ο笳Z法中乎串,代表“父類”
——本質(zhì)上就是代表父類這個“類”,而不是父類的“對象”速警;
其使用方式為:
parent::屬性或方法叹誉; //通常是靜態(tài)屬性或靜態(tài)方法,但有時候可能是實例屬性或?qū)嵗椒ǎ?
構(gòu)造方法和析構(gòu)方法調(diào)用上級同類方法的問題
1闷旧,如果一個類 有 構(gòu)造方法长豁,則實例化這個類的時候,就 不會 調(diào)用父類的構(gòu)造方法(如果有)忙灼;
2蕉斜,如果一個類沒有構(gòu)造方法,則實例化這個類的時候缀棍,就會自動調(diào)用父類的構(gòu)造方法(如果有);
3机错,如果一個類 有 析構(gòu)方法爬范,則銷毀這個類的時候,就 不會 調(diào)用父類的析構(gòu)方法(如果有)弱匪;
4青瀑,如果一個類沒有析構(gòu)方法,則銷毀這個類的時候萧诫,就會自動調(diào)用父類的析構(gòu)方法(如果有)斥难;
5,如果一個類中有構(gòu)造方法或析構(gòu)方法帘饶,則就可以去“手動”調(diào)用父類的同類方法(如果有)哑诊;
手動調(diào)用的語法形式總是這樣:
parent::構(gòu)造方法或析構(gòu)方法()
則,第5種情況及刻,parent在構(gòu)造方法中的一個典型代碼(寫法):
(在子類的構(gòu)造方法中镀裤,常常需要去調(diào)用父類的構(gòu)造方法竞阐,以簡化對象的初始化工作。)
覆蓋(override):
基本概念
覆蓋暑劝,又叫“重寫”:
含義:
將一個類從父類中繼承過來的屬性和方法“重新定義”——此時相當(dāng)于子類不想用父類的該屬性或方法骆莹,而是想要定義。
覆蓋的現(xiàn)實需要:
對于一個父類担猛,或許其屬性的現(xiàn)有數(shù)據(jù)(值)幕垦,子類覺得不合適,而需要有自己的新的描述傅联;
或許其方法先改,子類覺得也不合適,需要自己來重新定義該方法中要做到事纺且。
此時就可以使用覆蓋盏道。
重寫的基本要求:
訪問控制權(quán)限:
子類覆蓋的屬性或方法的訪問控制權(quán)限,不能“低于”父類的被覆蓋的屬性或方法的訪問控制權(quán)限:
具體來說:
父類: public 子類:只能是public
父類: protected 子類:可以說protected和public
父類: private 子類:不能覆蓋载碌!——既父類的私有成員猜嘱,不存在被子類覆蓋的可能。
方法的參數(shù)形式:
子類覆蓋父類的同名方法的時候嫁艇,參數(shù)要求跟父類保持一致朗伶;
特例:
構(gòu)造方法重寫的時候參數(shù)可以不一致
小注意:
雖然父類的私有屬性不能被覆蓋,但子類卻可以定義自己的跟父類同名的屬性步咪;
雖然父類的私有方法不能被覆蓋论皆,但子類也不能定義自己的同名方法;
最終類
最終類猾漫,其實就是一種特殊要求的類:要求該類不允許往下繼承下去点晴。
形式:
final class 類名{
//類的成員定義。悯周。粒督。跟一般類的定義一樣!
}
最終方法
最終方法禽翼,就是一個不允許下級類去覆蓋的方法M篱稀!
形式:
class 類名{
final function 方法名(形參列表...){ 闰挡。锐墙。。长酗。溪北。 }
}
設(shè)計模式
什么叫設(shè)計模式?
簡單來說,設(shè)計模式就是解決某個問題的一般性代碼的經(jīng)驗性總結(jié)刻盐。
類比來說:
它類似之前所學(xué)的“算法”:針對某種問題掏膏,使用某種特定的語法邏輯就可以完成該任務(wù)。
工廠模式
所謂工廠模式敦锌,就是這樣一個類(就是所謂的工廠類):
它可以根據(jù)“傳遞”給他的類名馒疹,而去生產(chǎn)出對應(yīng)的類的對象。
class A{}
class B{}
class FactoryClass{
static function GetObject($className){
$obj = new $className();
return $obj;
}
}
$obj1 = FactoryClass::GetObject("A");
$obj2 = FactoryClass::GetObject("B");
$obj3 = FactoryClass::GetObject("A");
單例模式:
例乙墙,就是實例(Instance)颖变,其實就是對象(object)
單例:就是一個對象;
單例模式:就是設(shè)計這樣一個類听想,這個類只能“創(chuàng)造”出它的一個對象(實例)腥刹;
class Singleton{
private function __construct(){
}
static private $instance = null;
static function ShareInstance(){
if(!isset(self::$instance)){
$obj = new self();
self::$instance = $obj;
return $obj;
}
return self::$instance;
}
}
- 設(shè)計一個MySQL數(shù)據(jù)庫操作類
設(shè)計目標(biāo):
1,該類一實例化汉买,就可以自動連接上mysql數(shù)據(jù)庫衔峰;
2,該類可以單獨去設(shè)定要使用的連接編碼(set names XXX)
3蛙粘,該類可以單獨去設(shè)定要使用的數(shù)據(jù)庫(use XXX)垫卤;
4,可以主動關(guān)閉連接出牧;
上述設(shè)計目錄穴肘,大致上相當(dāng)于如下幾行代碼:
$link = mysql_connect(“l(fā)ocalhost”, “root”, “123”);
mysql_query(“set names XXX”);
mysql_query(“use XXX”);
然后,后面就可以執(zhí)行各種sql語句來:
$r1 = mysql_query(“insert into ....”);
$r2 = mysql_query(“delete from .....”)
$r3 = mysql_query(“select * from ....”);
class MySQLDB{
publick $link = null;
function __construct($host,$port,$username,$password,$charset,$dbname){
$this->link = @mysql_connect("$host:$port","$username","$password") or die("connect failure!");
mysql_query("set names $charset");
mysql_query("use $dbname");
}
function setCharset($charset){
mysql_query("set names $charset")
}
function selectDB($dbname){
mysql_query("use $dbname");
}
function closeDB(){
mysql_close($this->link)
}
}
//使用
$host = "localhost";
$port = 3306;
$username = "root";
$password = "aaa"
$charset = "utf8";
$dbname = "info";
$db = new MySQLDB($host,$port,$username,$password,$charset,$dbname);
$result = mysql_query("select * from tab_int");
$db->setCharset("gbk");
$db->closeDB();
- 抽象類舔痕,抽象方法
抽象類:
是一個不能實例化的類评抚;
定義形式:
abstract class 類名{}
為什么需要抽象類:
它是為了技術(shù)管理而設(shè)計!
抽象方法:
是一個只有方法頭伯复,沒有方法體的方法定義形式慨代;
定義形式:
abstract function 方法名( 形參1,形參2啸如,.... )鱼响; //注意,這里必須有分號组底;
為什么需要抽象方法:
它也是為了技術(shù)管理而設(shè)計:要求下級類需要去實現(xiàn)這個方法的“具體做法”;
抽象類和抽象方法的細(xì)節(jié)
1筐骇,一個抽象方法债鸡,必須在抽象類中;
2铛纬,反過來厌均,抽象類中可以沒有抽象方法——雖然不常見;
3告唆,可見:抽象方法是為了規(guī)定下級類中“必須”要具體去完整某個工作(任務(wù))棺弊;
4晶密,下級類中繼承了上級類的抽象方法,則要么去“實現(xiàn)該方法的具體內(nèi)容”模她,要么自己也作為抽象類(即其繼承的抽象方法仍然是抽象的)稻艰;
5,子類實現(xiàn)父類的抽象方法的時候侈净,其形參也應(yīng)該跟父類保持一致尊勿,其訪問權(quán)限也不能更小畜侦;
——其原因其實這是“重寫現(xiàn)象”元扔,自然應(yīng)該遵循重寫的要求;
重載技術(shù)overloading
重載的基本概念
重載在“通常面向?qū)ο笳Z言”中的含義:
是指旋膳,在一個類(對象)中澎语,有多個名字相同但形參不同的方法的現(xiàn)象;
類似這樣:
class C{
function f1(){验懊。擅羞。。}
function f1($p1){鲁森。祟滴。。}
function f1($p1, $p2 ){歌溉。垄懂。。}
}
$c1 = new C();
$c1->f1();
$c1->f1(2);
$c1->f1(3,4);
重載在“php語言”中的含義:
是指痛垛,當(dāng)對一個對象或類使用其未定義的屬性或方法的時候草慧,其中的一些“處理機制”;
比如:
class A{
public $p1 = 1;
}
$a1 = new A();
echo $a1->p1; //1匙头;
echo $a1->p2; //出錯漫谷,未定義的屬性!
則:php中的重載技術(shù)蹂析,就是來應(yīng)對上述“出錯”的情況舔示,使代碼不出錯,而且還能“優(yōu)雅處理”电抚;
class A{
public $p = 1;
}
$a = new A();
echo $a->p; //1
echo $a->p2; //報錯
//處理
class A{
public $p = 1;
function __get($pro_name){
echo "調(diào)用了未定義字段"
}
}
$a = new A();
echo $a->p; //1
echo $a->p2; //不報錯,直接調(diào)用方法->調(diào)用了未定義字段
屬性重載
就是對一個對象的不存在的屬性進行使用的時候惕稻,這個類中預(yù)先設(shè)定好的應(yīng)對辦法(處理機制);
屬性蝙叛,本質(zhì)俺祠,就是變量,其只有4個操作:
取值:
當(dāng)對一個對象的不存在的屬性進行“取值”的時候,就會自動調(diào)用內(nèi)部方法:__GET()
賦值:
當(dāng)對一個對象的不存在的屬性進行“賦值”的時候蜘渣,就會自動調(diào)用內(nèi)部方法:__SET()
判斷(isset):
當(dāng)對一個對象的不存在的屬性進行isset()判斷的時候淌铐,就會自動調(diào)用內(nèi)部方法:__isset()
銷毀(unset):
當(dāng)對一個對象的不存在的屬性進行unset()銷毀的時候,就會自動調(diào)用內(nèi)部方法:__unset()
以上蔫缸,4個方法腿准,被稱為“魔術(shù)方法”;
__GET($屬性名):
在對一個對象的不存儲的屬性進行“取值”的時候捂龄,會自動調(diào)用的方法释涛;
我們其實是可以使用該方法來對這種“意外”情況進行某種特別的處理。
其中倦沧,該方法可以帶一個形參唇撬,表示這個要對之取值的不存在的屬性名(字符串);
__SET($屬性名展融,值):
當(dāng)對一個對象的不存在的屬性進行“賦值”的時候窖认,就會自動調(diào)用這個內(nèi)部的魔術(shù)方法;
它有2個形參告希,分別代表要對不存在的屬性進行賦值的時候的“屬性名”和“屬性值”扑浸;
這個方法,結(jié)合__GET方法燕偶,往往可以使我們定義的類喝噪,就有一種“可方便擴展屬性”的特性加缘。
即:類(或?qū)ο螅┑膶傩栽镒玻梢愿鼮榉奖阕杂桑?
class A{
protected $prop_list = array();
function __set($p,$v){
$this->prop_list[$p] = $v;
}
function __get($p){
return $this->prop_list[$p];
}
}
__ISSET($屬性名):
當(dāng)對一個對象的不存在的屬性進行isset()判斷的時候,就會自動調(diào)用內(nèi)部方法:__isset()值漫;
用法:
$v1 = isset($對象 -> 不存在的屬性); // 此時就會調(diào)用這個對象的所屬類中的魔術(shù)方法:__isset()
function __isset($prop){
$v = isset($this->prop_list[$prop]);
return $v;
}
__UNSET($屬性名):
當(dāng)對一個對象的不存在的屬性進行unset()銷毀操作的時候伯诬,就會自動調(diào)用內(nèi)部方法:__unset()
function __unset($prop){
unset($this->prop_list[$prop]);
}
方法重載
當(dāng)對一個對象的不存在的實例方法進行“調(diào)用”的時候晚唇,會自動調(diào)用類中的__call()這個魔術(shù)方法;
當(dāng)對一個類的不存在的靜態(tài)方法進行“調(diào)用”的時候盗似,會自動調(diào)用類中的__callstatic()這個靜態(tài)魔術(shù)方法哩陕;
class A{
function __call($method,$args){
echo "__call被調(diào)用了!"
}
}
利用php的重載技術(shù),實現(xiàn)通常的“方法重載”
- 接口 interface
什么是接口赫舒?
先看抽象類:
abstract class 類名 {
屬性1悍及;
屬性2;
.....
非抽象方法1接癌;
非抽象方法2心赶;
......
抽象方法1;
抽象方法2扔涧;
......
}
設(shè)想,將上述抽象類中“實在的成員”,刪除枯夜,即刪除那些非抽象的成員弯汰。則,自然該抽象類中湖雹,就只有抽象方法咏闪;
abstract class 類名 {
抽象方法1;
抽象方法2摔吏;
......
}
由此鸽嫂,可以理解為:這個抽象類,“太抽象了”征讲,幾乎自己什么都沒做据某,就光讓別人做什么。
那么:
接口就是這樣一個“天然不實在”的家伙:
接口诗箍,就是規(guī)定癣籽,里面只能放“抽象方法”和“常量”的一種類似類的語法結(jié)構(gòu);
——可見滤祖,接口就是“比抽象類更抽象的”一種語法結(jié)構(gòu)筷狼。
接口(interface)定義形式:
interface 接口名{
常量1;
常量2匠童;
.....
抽象方法1埂材;
抽象方法2;
.....
}
說明:
1汤求,可見俏险,接口中,只有常量(接口常量)和抽象方法兩種成員首昔;
2寡喝,接口常量的使用形式為: 接口名稱::常量名稱;
3勒奇,接口中的抽象方法预鬓,不要使用abstract修飾,也不需要使用訪問控制修飾符赊颠,因為其天然就是public
為什么需要接口格二?
面向?qū)ο缶幊趟枷胧菍Α艾F(xiàn)實世界”的描述(模擬)!
現(xiàn)實世界往往都都是多繼承的竣蹦;
但:
出于降低類跟類之間關(guān)系的復(fù)雜度的考慮顶猜,就將語言設(shè)計為單繼承的;
但這樣痘括,就無法表達出現(xiàn)實世界的多繼承特性长窄;
則:
接口就是對沒有多繼承的類之間關(guān)系的一個補充滔吠;
因為:接口可以實現(xiàn)“多繼承”——但此時不稱為繼承而已,而是稱為“實現(xiàn)”挠日;
即:
接口1 -->> 類1疮绷;
就稱為:類1實現(xiàn)了接口1;
其本質(zhì)嚣潜,其實就是類1中冬骚,有了接口1中“特征信息”;
使用形式:
形式為:
class 類名 implements 接口名1懂算, 接口名2只冻, ....{
//類的定義。
}
這里计技,叫做喜德,類實現(xiàn)了接口。
其中酸役,接口跟接口之間住诸,也可以繼承,跟類之間的繼承:
interface 接口1 extends 接口2{
//接口的成員定義涣澡;贱呐。。入桂。奄薇。
}
進一步完善mysqldb工具類:
完善分2個方面:
1,現(xiàn)有已經(jīng)完成的功能抗愁,做優(yōu)化處理馁蒂;
2,添加更多的功能蜘腌,要求繼續(xù)實現(xiàn)如下功能:
2.1:用該類的對象可以執(zhí)行任意的增刪改語句沫屡,并返回布爾值;
2.2:用該類的對象可以執(zhí)行返回一行數(shù)據(jù)的“查詢語句”:結(jié)果是一個一維數(shù)組撮珠,類似這樣:
array( ‘id’=>3, ‘name’=>’張三’, ‘a(chǎn)ge’ => 18, ‘edu’=>’大學(xué)’ );
2.3:用該類的對象可以執(zhí)行返回多行數(shù)據(jù)的“查詢語句”:結(jié)果是一個二維數(shù)組沮脖,類似這樣:
array(
0=>array( ‘id’=>3, ‘name’=>’張三’, ‘a(chǎn)ge’ => 18, ‘edu’=>’大學(xué)’ ),
1=>array( ‘id’=>4, ‘name’=>’張四’, ‘a(chǎn)ge’ => 14, ‘edu’=>’中學(xué)’ )芯急,
2=>array( ‘id’=>7, ‘name’=>’張七’, ‘a(chǎn)ge’ => 17, ‘edu’=>’小學(xué)’ )
)
2.4:用該類的對象可以執(zhí)行返回一個數(shù)據(jù)的“查詢語句”:結(jié)果是一個數(shù)據(jù)值勺届,其sql語句常常類似這樣: select name from Users where id = 1; 或: select count(*) as c from 表名;
- 類的自動加載
含義:
當(dāng)某行代碼需要一個類的時候娶耍,php的內(nèi)部機制可以做到“自動加載該類文件”免姿,以滿足該行需要一個類的這種需求。
什么時候需要一個類榕酒?
1胚膊,new一個對象的時候故俐;
2,使用一個類的靜態(tài)方法的時候紊婉;
3购披,定義一個類(B)并以另一個類(A)作為父類的時候;
function __autoload($name){
require_once './'.$name.'.class.php'
}
$config = array(
"host"=>"localhost",
"port"=>3306,
"username"=>"root",
"password"=>"aaa",
"charset"=>"utf8",
"dbname"=>"db123"
);
$db = MySQLDB::ShareInstance($config);
條件和要求
1肩榕, 當(dāng)需要一個類的時候,就會自動調(diào)用某個函數(shù)(默認(rèn)是__autoload)惩妇,并傳入所需要的類的名字
2株汉, 一個類應(yīng)該保存到一個獨立的“類文件中”:即其中只有該類的定義,沒有別的代碼歌殃;
3,習(xí)慣上氓皱,類文件的命名要有一定的“規(guī)則”路召,通常是:類名.class.php
4波材,通常股淡,我們需要將各種類,存儲在一些特定的目錄中廷区,以方便確定其位置唯灵!
5,在該自動加載的函數(shù)中隙轻,“充分”使用傳過來的類名埠帕,以構(gòu)建一個合適的文件路徑并載入;
自定義自動加載函數(shù):
剛才玖绿,__autoload()函數(shù)敛瓷,是系統(tǒng)內(nèi)部的自動加載函數(shù),我們只是定義其函數(shù)體斑匪。
但:
我們可以使用更多函數(shù)(自定義的)呐籽,來實現(xiàn)更靈活的自動加載!
基本模式為:
spl_autoload_register(“函數(shù)1”); //聲明“函數(shù)1”作為自動加載函數(shù)秤标;
spl_autoload_register(“函數(shù)2”); //聲明“函數(shù)2”也作為自動加載函數(shù)绝淡;
.........
然后,就去定義這些函數(shù)苍姜,跟定義__autoload()函數(shù)一樣:
function 函數(shù)1( $class_name ){
//.......
}
function 函數(shù)2( $class_name ){
//.......
}
.............
這樣牢酵,系統(tǒng)就會一次調(diào)用這些自動加載函數(shù)去加載所需要的類,直到加載成功衙猪!
spl_autoload_register("autoload1");
spl_autoload_register("autoload2");
function autoload1($class_name){
$file = './class/'.$class_name.".class.php";
if(file_exists($file)){
include_once $file;
}
}
function autoload2($class_name){
$file = './lib/'.$class_name.".class.php";
if(file_exists($file)){
include_once $file;
}
}
對象的復(fù)制(克骡梢摇)
$obj1 = new A();
$obj1->p1 = 11;
$obj2 = $obj1; //值傳遞
//則布近,現(xiàn)在有幾個對象?——1個對象丝格!
當(dāng)然:
$obj3 = & $obj1;
結(jié)果撑瞧,還是一個對象!
對象的克隆語法显蝌,就是用于將一個對象“制作”雙份的語法预伺,類似之前普通數(shù)據(jù)的“值傳遞”;
語法:
$obj2 = clone $obj1; //這樣曼尊,就有一個跟$obj1完全一樣的新的對象酬诀。
對象的遍歷
對象的遍歷,跟數(shù)組的遍歷骆撇,一樣瞒御!
其實,只能遍歷出對象的“實例屬性數(shù)據(jù)”
foreach( $對象名 as $key => $value){
//這里就可以處理$key和$value
//但注意:
1, $key表示的是對象 的 “屬性”神郊,$value是其對應(yīng)值肴裙;
2, 這里能夠遍歷出來的屬性,只能是在該范圍中的“可訪問屬性”(就是要考慮訪問控制權(quán)限)
}
將一個對象的所有屬性都遍歷出來
class A{
public $p1 = 1;
protected $p2 = 2;
private $p3 = 3;
static $p4 = 4;
function showAllProperties(){
foreach($this as $key=>$vlue){
...
}
}
}
PHP內(nèi)置標(biāo)準(zhǔn)類
php語言內(nèi)部涌乳,有“很多現(xiàn)成的類”蜻懦,其中有一個,被稱為“內(nèi)置標(biāo)準(zhǔn)類”夕晓。
這個類“內(nèi)部”可以認(rèn)為什么都沒有阻肩,類似這樣:
class stdclass{ }
其作用,可以用于存儲一些臨時的簡單的數(shù)據(jù):
$obj1->pp1 = 1;
$obj1->port = ‘3306’;
也可以用于類型轉(zhuǎn)換時用于存儲數(shù)據(jù)运授,如下節(jié)所示
其他數(shù)據(jù)類型轉(zhuǎn)換為對象類型
其他數(shù)據(jù)類型轉(zhuǎn)換為對象類型烤惊,得到的結(jié)果是:內(nèi)置標(biāo)準(zhǔn)類(stdclass)的一個對象!
語法形式為:
$obj1 = (object) 其他類型數(shù)據(jù)吁朦;
? 數(shù)組轉(zhuǎn)換為對象:數(shù)組的鍵名當(dāng)作屬性名柒室,值為對應(yīng)值;
注意:數(shù)字下標(biāo)的數(shù)據(jù)元素逗宜,轉(zhuǎn)換為對象后的屬性雄右,無法通過對象語法獲取,因此不推薦轉(zhuǎn)換纺讲。
? null轉(zhuǎn)換為對象:空對象擂仍;
$obj1 = (object)null;
? 其他標(biāo)量數(shù)據(jù)轉(zhuǎn)換為對象:屬性名為固定的“scalar”,值為該變量的值:
類型約束
什么叫類型約束熬甚?
就是要求某個變量只能使用(接收逢渔,存儲)某種指定的數(shù)據(jù)類型;
php屬于“弱類型語言”乡括,通常不支持類型約束肃廓;
相應(yīng)的智厌,強類型語言,類型約束卻是其“基本特征”盲赊。
php中铣鹏,只支持局部的部分類型約束
php中,只支持在函數(shù)(或方法)的形參上哀蘑,設(shè)定類型的約束目標(biāo)诚卸,形式如下:
function 方法名(【要求使用的類型】$p1 , 【要求使用的類型】$p2, ..... ){
//..........
}
說明:
1,定義一個函數(shù)(方法)時绘迁, 一個形參惨险,可以使用類型約束,也可以不使用脊髓;
2,如果使用了類型約束栅受,則對應(yīng)的該實參數(shù)據(jù)将硝,就必須是要求的那種類型。
3屏镊,能夠使用的類型約束依疼,其實非常少,只有以下幾種可用:
數(shù)組: array而芥,
對象:使用類的名稱律罢,表示,傳遞過來的實參棍丐,必須是該類的實例误辑;
接口: 使用接口的名稱,表示歌逢,傳遞過來的實參巾钉,必須是實現(xiàn)了該接口的類的實例
單例類的加強:禁止克隆
對于一個類的對象,如果使用“clone運算符”秘案,就會克隆出一個跟當(dāng)前對象完全一樣的新對象出來砰苍,
并且:
此時還會自動調(diào)用該類中的魔術(shù)方法:_ _c l o n e ();只要其中有該方法阱高;
則赚导,要想實現(xiàn)單例類,就應(yīng)該對這個單例類的對象“禁止克隆”赤惊,做法是:
私有化這個魔術(shù)方法:_ _c l o n e ()吼旧;
與類有關(guān)的其他魔術(shù)方法
序列化與反序列化技術(shù)
含義:
序列化:
就是將一個變量所代表的“內(nèi)存”數(shù)據(jù),轉(zhuǎn)換為“字符串”形式并持久保存在硬盤上的一種做法未舟。
反序列化:
就是將序列化之后保存在硬盤上的“字符串?dāng)?shù)據(jù)”黍少,恢復(fù)為其原來的內(nèi)存形式的變量數(shù)據(jù)的一種做法寡夹。
序列化的做法:
$v1 = 123; //這是一個變量,代表任意的內(nèi)存數(shù)據(jù)
$s1 = serialize( $v1 ); //將任何類型的變量數(shù)據(jù)厂置,轉(zhuǎn)換為“字符串”
file_put_contents( ‘要保存的目標(biāo)文本文件’, $s1); //將該字符串菩掏,保存到一個文件里(就是硬盤數(shù)據(jù))
反序列化的做法:
$s1 = file_get_contents( ‘保存序列化數(shù)據(jù)的目標(biāo)文本文件’); //從一個文件里讀出其中的所有字符
$v1 = unserialize( $s1 ); //將該字符串?dāng)?shù)據(jù),反序列化轉(zhuǎn)換為變量(數(shù)據(jù))
__sleep():用于對象的序列化:
1昵济,對一個對象進行序列化智绸,只能將其屬性數(shù)據(jù)“保存起來”,而方法被忽略(方法不是數(shù)據(jù))
2访忿,對象的序列化的時候瞧栗,會自動調(diào)用該對象所屬類的這個魔術(shù)方法:__sleep()(前提是有該方法)。
且海铆,此時迹恐,該方法必須返回一個數(shù)組,數(shù)組中是“計劃”要進行序列化的屬性名卧斟;
__wakeup:用于對象的反序列化:
1殴边,對一個對象進行反序列化,其實是恢復(fù)其原來保存起來的屬性數(shù)據(jù)珍语,而且锤岸,此時必然需要依賴該對象原本的所屬類;
2板乙,對象在反序列化的時候是偷,會自動調(diào)用該對象所屬類的這個魔術(shù)方法:__wakeup()
__tostring()魔術(shù)方法——比較常用!
含義:
將一個對象“當(dāng)做”一個字符串來使用的時候募逞,會自動調(diào)用該方法蛋铆,并且在該方法中,可以返回一定的字符串放接,以表明該對象轉(zhuǎn)換為字符串之后的結(jié)果戒职。
注意:
如果沒有定義該方法,則對象無法當(dāng)做字符串來使用透乾!
__invoke()魔術(shù)方法:
將對象當(dāng)作函數(shù)來使用的時候洪燥,會自動調(diào)用該方法。通常不推薦這么做乳乌。
class A{
function __invoke(){
echo “<br />我是一個對象呀捧韵,你別當(dāng)我是一個函數(shù)來隨便調(diào)用!”;
}
}
$obj1 = new A();
$obj1(); //此時就會調(diào)用類中的方法:__invoke()
其他零碎:
與類有關(guān)的魔術(shù)常量:
以前學(xué)過的魔術(shù)常量:
__FILE__
__DIR__
__LINE__
現(xiàn)在:
__CLASS__: 代表當(dāng)前其所在的類的類名汉操;
__METHOD__:代表其當(dāng)前所在的方法名再来;
與類有關(guān)的系統(tǒng)函數(shù):
class_exists(“類名”), 判斷一個類是否存在(是否定義過)
interface_exists(“接口名”), 判斷一個接口是否存在(是否定義過)
get_class( $obj ), 獲得某個對象$obj 的所屬類
get_parent_class($obj ), 獲得某個對象$obj 的所屬類的父類
get_class_methods(), 獲得一個類的所有方法名,結(jié)果是一個數(shù)組,里面存儲的是這些方法的名稱
get_class_vars(), 獲得一個類的所有屬性名芒篷。結(jié)果是一個數(shù)組搜变,里面存儲的是這些屬性的名稱get_declared_classes() 獲得“整個系統(tǒng)”所定義的所有類名;
與對象有關(guān)的系統(tǒng)函數(shù):
is_object( $obj ): 判斷某個變量是否是一個對象针炉;
get_object_vars( $obj ):獲得一個對象的所有屬性挠他;結(jié)果是一個數(shù)組,里面存儲的是這些屬性的名稱
與類有關(guān)的運算符:
new篡帕,
instanceof: 判斷一個“變量”(對象殖侵,數(shù)據(jù)),是否是某個類的“實例”镰烧;
示意如下:
class A {}
class B {}
class C extends A{}
$a1 = new A();
$b1 = new B();
$c1 = new C();
$v1 = $a1 instanceof A ; //結(jié)果是true
$v2 = $b1 instanceof A ; //結(jié)果是false
$v3 = $c1 instanceof C ; //結(jié)果是true
$v4 = $c1 instanceof A ; //結(jié)果是true
——推論:一個類的對象拢军,必然也屬于這個類的上級類的對象;
static關(guān)鍵字的新用法和總結(jié):
static這個關(guān)鍵字怔鳖,也可以像“self”一樣茉唉,代表“當(dāng)前類”,用于訪問一個類的“靜態(tài)屬性或靜態(tài)方法”结执;
但度陆,
static,在應(yīng)用中昌犹,更靈活,因此更常見览芳!
因為static斜姥,它代表的是“調(diào)用”當(dāng)前方法的類,而不是“其代碼所在的類”:
self它就比較死板沧竟,只代表這個單詞本身所在位置的所在類铸敏。
面向?qū)ο缶幊趟枷氲?個特征:
封裝:
無非是一個大的指向思想,目的是為了將一個類設(shè)計得更為健壯悟泵!
其基本做法是:
盡可能地將一個類的成員私有化杈笔,只開放那些必不可少的對外的屬性或方法,能private的就不要protected糕非。能protected就不要public
繼承:
是面向?qū)ο蟮幕舅枷牒突咀龇ā?繼承是代碼重用的一種重要機制蒙具。
多態(tài):
多態(tài),就是“多種形態(tài)”朽肥,其實指的是禁筏,現(xiàn)實世界的“豐富多彩的表現(xiàn)形式”,比如:
人在吃飯衡招;
豬在吃食篱昔;
魚在進食;
小雞啄米;
州刽。空执。。穗椅。
他們都是“吃”這個行為辨绊!
在實際代碼(應(yīng)用)中,多態(tài)常常有兩種表現(xiàn)形式:
1房待, 不同對象邢羔,使用相同的方法,會表現(xiàn)為不同的結(jié)果桑孩!
2拜鹤, 同一個對象,使用相同的方法流椒,也可能會表現(xiàn)為不同的結(jié)果——這其實是“方法重載現(xiàn)象”
面向過程編程:
其基本特征是:
將要完成的任務(wù),分割為若干個步驟:
第1步:做什么喻粹。。厂抽。
第2步:做什么。暗甥。坎怪。
.......
最后岖沛,做完了暑始,任務(wù)完成!
面向?qū)ο缶幊蹋篛OP: Object Oriented Program(面向?qū)ο缶幊蹋?其基本特征是:
將要完成的任務(wù)婴削,“分派”給不同的“對象”去做;
某對象1:會做什么牙肝。唉俗。。
某對象2:會做什么配椭。虫溜。。
........
程序一旦啟動股缸,則各個對象“各司其職”衡楞,相互配合就完成了任務(wù)。
面向?qū)ο笾械幕靖拍?類和對象
對象: 萬物皆對象敦姻;
類: 任何對象瘾境,都可以人為“規(guī)定”為某種類型(類別);
class Person{
var $name ;
var $age;
var $edu;
}
我:
姓名:羅XX镰惦,
年齡40迷守,
學(xué)歷:大學(xué);
王亮:
姓名:王亮
年齡:20旺入;
學(xué)歷:大學(xué)兑凿;
class Teacher{
var $name ;
var $age;
var $edu;
var $major; //專業(yè)
}
可見:
? 類是描述一類事物的一個總稱,是具有相同特征特性的該類事物的一個通用名字(稱呼)茵瘾;
? 對象是一個明確的具體的“物體”礼华,是某個類中的一個“實物”(相對來說,類就是一種抽象的泛稱)拗秘。對象離不開類圣絮,或者說,對象一定隸屬于某個類——有類才有對象聘殖,先有類再有對象晨雳。
屬性和方法
屬性:就是原來的“變量”,只是現(xiàn)在它“隸屬于”一個類了奸腺,即寫在一個類中餐禁,就稱為屬性;
方法:就是原來的“函數(shù)”突照,只是現(xiàn)在它“隸屬于”一個類了帮非,即寫在一個類中,就稱為方法;
注意:屬性和方法末盔,已經(jīng)不能“自由使用”了筑舅,而是都要通過這個類或這個類的對象去使用。
使用屬性陨舱,就把它當(dāng)做一個“變量”去使用就好了翠拣,只是需要該形式:對象->屬性名;
使用方法游盲,就把它當(dāng)做一個“函數(shù)”去使用就好了误墓,只是需要該形式:對象->函數(shù)名(實參列表...)
創(chuàng)建對象的幾種形式
class C1{
var $p1 = 1; //定義一個屬性;
}
形式1:
$o1 = new C1(); //通過一個類益缎,去new出一個對象
形式2:
$o2 = new $o1(); //通過一個對象谜慌,去new出一個對象——其實是new出來的是舊對象所述類的一個新對象套腹。
形式3:
$s1 = “C1”; //只是一個字符串變量而已藕溅;
$o3 = new $s1(); //這就是所謂的“可變類”——無非就是類的名字是一個變量而已。
形式4:
$o4 = new self(); //self表示“當(dāng)前類本身”拍柒,它只能出現(xiàn)在一個類的方法中令哟。
對象的傳值方式:
為什么對于對象恼琼,值傳遞和引用傳遞,這個情況下励饵,他們似乎沒有區(qū)別驳癌??役听?
這要從對象的數(shù)據(jù)的存儲方式來理解:
$o1 = new C1(); //這里創(chuàng)建一個對象o1颓鲜,其存儲結(jié)果
這里,實際上典予,變量$o1中甜滨,存儲的數(shù)據(jù)只是一個“對象編號#1”,這個對象編號瘤袖,才會去指向?qū)ο髷?shù)據(jù)new C1(); 該編號數(shù)據(jù)衣摩,我們不能控制,只是系統(tǒng)內(nèi)部的分配捂敌。
在語法上艾扮,對對象變量進行的屬性進行操作,其實就是通過該編號來指向?qū)ο蠖僮鞯摹?$o1->p1 = 2; //此時占婉,就是通過對象編號#1去修改了對象(new C1() )本身的內(nèi)部數(shù)據(jù).
echo $o2->p1; //此時相當(dāng)于取得變量$o2所包含的編號#1中所指向的對象(new C1() )的內(nèi)部數(shù)據(jù)p1
類中成員
類中成員概述
面向?qū)ο缶幊膛葑欤切枰ㄟ^“對象”去做什么事情(以完成某種任務(wù));
而:
對象總是來源于類逆济;
所以:
面向?qū)ο蟮木幊套糜瑁磺卸际菑亩x類開始磺箕;
類中成員分為3大類:
屬性:
方法:
常量:
形式上,大致如下:
class 類名 {
常量定義1抛虫;
常量定義2松靡;
.......
屬性定義1;
屬性定義2建椰;
........
方法定義1雕欺;
方法定義2;
.......
}
說明:
以上各項广凸,沒有順序問題阅茶;習(xí)慣上,其實常量放前面谅海,然后是屬性,然后是方法蹦浦;
詳細(xì)一點扭吁,就又分為:
屬性:
普通屬性;//一般屬性盲镶,實例屬性
靜態(tài)屬性侥袜;
方法:
普通方法;//一般方法溉贿,實例方法
靜態(tài)方法枫吧;
構(gòu)造方法;
析構(gòu)方法宇色;
常量:
類常量
當(dāng)在一個類中定義一個常量時九杂,該常量就稱為“類常量”——本質(zhì)其實還是常量;
定義形式:
class 類名{
const 常量名 = 常量值宣蠕;
//不可以使用define()來定義例隆!
}
使用形式:
常量的使用,是通過類名抢蚀,并使用范圍解析符(::)來取用的镀层;
類名::常量名;
普通屬性(實例屬性):
實例的單詞為:instance
實例皿曲,其實也叫做“對象”唱逢;
普通(實例)屬性,就是一個可以在該類實例化出的對象上使用的屬性屋休!
定義形式:
class 類名{
var $屬性名 = 初始值坞古;
var $屬性名; //這個屬性沒有初始值博投;
//上述的var 還可以使用public來代替绸贡,比如:
public $屬性名 = 初始值;
public $屬性名; //這個屬性沒有初始值听怕;
}
使用形式:
是通過該類的對象捧挺,來使用普通屬性(實例屬性):
$對象->屬性名;
因為尿瞭,屬性的本質(zhì)就是變量闽烙,則其就可以當(dāng)做一個變量來看待和使用,比如:
$v1 = $對象->屬性名声搁;
echo $對象->屬性名黑竞;
$v2 = $對象->屬性名 * 3 + 5; //進行計算
靜態(tài)屬性:
靜態(tài)屬性,本質(zhì)上也是“變量”疏旨,但其有一個特點就是:該變量只隸屬于“類”很魂,即:
一個類中的一個靜態(tài)屬性,就只有“一份數(shù)據(jù)”檐涝;
但:
一個類中的一個實例屬性遏匆,就可以有“多份數(shù)據(jù)”——每創(chuàng)建一個對象出來,就會有一份數(shù)據(jù)谁榜;
定義形式:
class 類名{
static $屬性名 = 初始值幅聘;
static $屬性名; //這個屬性沒有初始值窃植;
}
使用形式:
使用類名和范圍解析符(::)來對靜態(tài)屬性進行操作:
類名::$靜態(tài)屬性名帝蒿; //注意:屬性名帶$符號
對比1:
常量的使用:類名::常量名;
對比2:
實例屬性的使用:對象名->實例屬性名巷怜; //注意:屬性名不帶$符號
1葛超,實例屬性,是每個對象都可以不一樣的數(shù)據(jù)丛版,也是每個對象都“獨自擁有”的數(shù)據(jù)巩掺;
2,靜態(tài)屬性页畦,他不屬于任何一個對象胖替,而只屬于該類本身,也可以理解為為所有對象所共有的數(shù)據(jù)豫缨;
普通方法(實例方法)
一個類中定義的方法独令,可以為這個類的所有對象調(diào)用的方法。也可以理解為好芭,這個類的所有對象燃箭,都各自有自己的一個該方法;
定義形式:
class 類名{
function 方法名(形參1舍败,形參2招狸,.... ){
//方法體敬拓。。裙戏。
}
}
調(diào)用形式:
$對象名->方法名(實參1乘凸,實參2,....)累榜;
靜態(tài)方法
一個類中定義的方法营勤,只隸屬于這個類本身,而不是隸屬于這個類的對象壹罚。
定義形式:
class 類名{
static function 方法名(形參1葛作,形參2,.... ){
//方法體猖凛。赂蠢。。
}
}
調(diào)用形式:
類名::方法名(實參1辨泳,實參2客年,....);
構(gòu)造方法(__construct):
構(gòu)造方法漠吻,是一個特殊的方法:
1,名字是固定的:_ _construct司恳;
2途乃,該方法通常都不要我們自己調(diào)用,而是在new一個對象的時候會自動調(diào)用扔傅。
3耍共,該方法主要的目的是為了在new一個對象的時候,給該對象設(shè)置一些“初始值”(初始化工作)猎塞;
4试读,構(gòu)造方法的參數(shù)沒有規(guī)定,通常是根據(jù)實際的需要來定義荠耽,目的是為了對象屬性數(shù)據(jù)的初始化钩骇;
析構(gòu)方法(__destruct):
說明:
1,析構(gòu)方法是一個特殊的方法铝量,名字為固定的詞:_ _desctruct
2倘屹,析構(gòu)方法是在一個對象被“銷毀”的時候會自動被調(diào)用的方法——我們無法調(diào)用它;
3慢叨,析構(gòu)方法不能帶參數(shù)(形參)纽匙,但方法中也可以使用$this這個詞,代表“當(dāng)前對象”拍谐;
對象在哪些情況下會被銷毀烛缔?
1馏段,如果程序結(jié)束,所有變量都會被銷毀践瓷,自然院喜,變量所代表的對象也會被銷毀;
對象銷毀的順序当窗,默認(rèn)情況下够坐,跟其創(chuàng)建的順序相反;
2崖面,當(dāng)一個對象沒有任何變量“指向”它的時候元咙,即使程序還沒有結(jié)束,也會被銷毀巫员;
基本概念
將一個類A中的特性信息庶香,傳遞到另一個類B中,此時就稱為:
B繼承A
A派生出B
class A{
}
class B extends A{
}
幾個基本概念
? 繼承:一個類從另一個已有的類獲得其特性简识,稱為繼承赶掖。
? 派生:從一個已有的類產(chǎn)生一個新的類,稱為派生七扰。
? 父類/子類:已有類為父類奢赂,新建類為子類。父類又可以稱為“基類”颈走,上級類膳灶,子類又稱為派生類,下級類立由,
? 單繼承:一個類只能從一個上級類繼承其特性信息轧钓。PHP和大多數(shù)面向?qū)ο蟮恼Z言都是單繼承模式。C++是多繼承锐膜。
? 擴展:在子類中再來定義自己的一些新的特有的特性信息(屬性毕箍,方法和常量)。沒有擴展道盏,繼承也就沒有意義了而柑。
訪問控制修飾符
形式:
class 類名{
訪問控制修飾符 屬性或方法定義;
}
有3個訪問修飾符:
? public公共的:在所有位置都可訪問(使用)捞奕。
? protected受保護的:只能再該類內(nèi)部和該類的子類或父類中訪問(使用)牺堰。
? private私有的:只能在該類內(nèi)部訪問(使用)。
他們的作用是:用來“限制”其所修飾的成員的“可訪問性”颅围;
可訪問性:
就是在代碼中使用這樣兩種語法形式的“有效性”(合法性):
對象->實例屬性或方法伟葫;
類::靜態(tài)屬性或方法;
訪問控制修飾符院促,需要結(jié)合使用該語法形式的所在位置筏养,才能確定是否可訪問斧抱。
有3個訪問位置(范圍):
某個類的內(nèi)部:
某個類的繼承類的內(nèi)部:
某個類的外部:
1,public修飾的成員渐溶,哪里都能訪問辉浦;
2,類的內(nèi)部茎辐,可以訪問任何級別的成員宪郊;
3,public具有最寬泛的可訪問性拖陆;private具有最狹小的可訪問性弛槐;protecte則居中;
parent關(guān)鍵詞
parent表示“父母”的意思依啰,在面向?qū)ο笳Z法中乎串,代表“父類”
——本質(zhì)上就是代表父類這個“類”,而不是父類的“對象”速警;
其使用方式為:
parent::屬性或方法叹誉; //通常是靜態(tài)屬性或靜態(tài)方法,但有時候可能是實例屬性或?qū)嵗椒ǎ?
構(gòu)造方法和析構(gòu)方法調(diào)用上級同類方法的問題
1闷旧,如果一個類 有 構(gòu)造方法长豁,則實例化這個類的時候,就 不會 調(diào)用父類的構(gòu)造方法(如果有)忙灼;
2蕉斜,如果一個類沒有構(gòu)造方法,則實例化這個類的時候缀棍,就會自動調(diào)用父類的構(gòu)造方法(如果有);
3机错,如果一個類 有 析構(gòu)方法爬范,則銷毀這個類的時候,就 不會 調(diào)用父類的析構(gòu)方法(如果有)弱匪;
4青瀑,如果一個類沒有析構(gòu)方法,則銷毀這個類的時候萧诫,就會自動調(diào)用父類的析構(gòu)方法(如果有)斥难;
5,如果一個類中有構(gòu)造方法或析構(gòu)方法帘饶,則就可以去“手動”調(diào)用父類的同類方法(如果有)哑诊;
手動調(diào)用的語法形式總是這樣:
parent::構(gòu)造方法或析構(gòu)方法()
則,第5種情況及刻,parent在構(gòu)造方法中的一個典型代碼(寫法):
(在子類的構(gòu)造方法中镀裤,常常需要去調(diào)用父類的構(gòu)造方法竞阐,以簡化對象的初始化工作。)
覆蓋(override):
基本概念
覆蓋暑劝,又叫“重寫”:
含義:
將一個類從父類中繼承過來的屬性和方法“重新定義”——此時相當(dāng)于子類不想用父類的該屬性或方法骆莹,而是想要定義。
覆蓋的現(xiàn)實需要:
對于一個父類担猛,或許其屬性的現(xiàn)有數(shù)據(jù)(值)幕垦,子類覺得不合適,而需要有自己的新的描述傅联;
或許其方法先改,子類覺得也不合適,需要自己來重新定義該方法中要做到事纺且。
此時就可以使用覆蓋盏道。
重寫的基本要求:
訪問控制權(quán)限:
子類覆蓋的屬性或方法的訪問控制權(quán)限,不能“低于”父類的被覆蓋的屬性或方法的訪問控制權(quán)限:
具體來說:
父類: public 子類:只能是public
父類: protected 子類:可以說protected和public
父類: private 子類:不能覆蓋载碌!——既父類的私有成員猜嘱,不存在被子類覆蓋的可能。
方法的參數(shù)形式:
子類覆蓋父類的同名方法的時候嫁艇,參數(shù)要求跟父類保持一致朗伶;
特例:
構(gòu)造方法重寫的時候參數(shù)可以不一致
小注意:
雖然父類的私有屬性不能被覆蓋,但子類卻可以定義自己的跟父類同名的屬性步咪;
雖然父類的私有方法不能被覆蓋论皆,但子類也不能定義自己的同名方法;
最終類
最終類猾漫,其實就是一種特殊要求的類:要求該類不允許往下繼承下去点晴。
形式:
final class 類名{
//類的成員定義。悯周。粒督。跟一般類的定義一樣!
}
最終方法
最終方法禽翼,就是一個不允許下級類去覆蓋的方法M篱稀!
形式:
class 類名{
final function 方法名(形參列表...){ 闰挡。锐墙。。长酗。溪北。 }
}
設(shè)計模式
什么叫設(shè)計模式?
簡單來說,設(shè)計模式就是解決某個問題的一般性代碼的經(jīng)驗性總結(jié)刻盐。
類比來說:
它類似之前所學(xué)的“算法”:針對某種問題掏膏,使用某種特定的語法邏輯就可以完成該任務(wù)。
工廠模式
所謂工廠模式敦锌,就是這樣一個類(就是所謂的工廠類):
它可以根據(jù)“傳遞”給他的類名馒疹,而去生產(chǎn)出對應(yīng)的類的對象。
class A{}
class B{}
class FactoryClass{
static function GetObject($className){
$obj = new $className();
return $obj;
}
}
$obj1 = FactoryClass::GetObject("A");
$obj2 = FactoryClass::GetObject("B");
$obj3 = FactoryClass::GetObject("A");
單例模式:
例乙墙,就是實例(Instance)颖变,其實就是對象(object)
單例:就是一個對象;
單例模式:就是設(shè)計這樣一個類听想,這個類只能“創(chuàng)造”出它的一個對象(實例)腥刹;
class Singleton{
private function __construct(){
}
static private $instance = null;
static function ShareInstance(){
if(!isset(self::$instance)){
$obj = new self();
self::$instance = $obj;
return $obj;
}
return self::$instance;
}
}
設(shè)計目標(biāo):
1,該類一實例化汉买,就可以自動連接上mysql數(shù)據(jù)庫衔峰;
2,該類可以單獨去設(shè)定要使用的連接編碼(set names XXX)
3蛙粘,該類可以單獨去設(shè)定要使用的數(shù)據(jù)庫(use XXX)垫卤;
4,可以主動關(guān)閉連接出牧;
上述設(shè)計目錄穴肘,大致上相當(dāng)于如下幾行代碼:
$link = mysql_connect(“l(fā)ocalhost”, “root”, “123”);
mysql_query(“set names XXX”);
mysql_query(“use XXX”);
然后,后面就可以執(zhí)行各種sql語句來:
$r1 = mysql_query(“insert into ....”);
$r2 = mysql_query(“delete from .....”)
$r3 = mysql_query(“select * from ....”);
class MySQLDB{
publick $link = null;
function __construct($host,$port,$username,$password,$charset,$dbname){
$this->link = @mysql_connect("$host:$port","$username","$password") or die("connect failure!");
mysql_query("set names $charset");
mysql_query("use $dbname");
}
function setCharset($charset){
mysql_query("set names $charset")
}
function selectDB($dbname){
mysql_query("use $dbname");
}
function closeDB(){
mysql_close($this->link)
}
}
//使用
$host = "localhost";
$port = 3306;
$username = "root";
$password = "aaa"
$charset = "utf8";
$dbname = "info";
$db = new MySQLDB($host,$port,$username,$password,$charset,$dbname);
$result = mysql_query("select * from tab_int");
$db->setCharset("gbk");
$db->closeDB();
抽象類:
是一個不能實例化的類评抚;
定義形式:
abstract class 類名{}
為什么需要抽象類:
它是為了技術(shù)管理而設(shè)計!
抽象方法:
是一個只有方法頭伯复,沒有方法體的方法定義形式慨代;
定義形式:
abstract function 方法名( 形參1,形參2啸如,.... )鱼响; //注意,這里必須有分號组底;
為什么需要抽象方法:
它也是為了技術(shù)管理而設(shè)計:要求下級類需要去實現(xiàn)這個方法的“具體做法”;
抽象類和抽象方法的細(xì)節(jié)
1筐骇,一個抽象方法债鸡,必須在抽象類中;
2铛纬,反過來厌均,抽象類中可以沒有抽象方法——雖然不常見;
3告唆,可見:抽象方法是為了規(guī)定下級類中“必須”要具體去完整某個工作(任務(wù))棺弊;
4晶密,下級類中繼承了上級類的抽象方法,則要么去“實現(xiàn)該方法的具體內(nèi)容”模她,要么自己也作為抽象類(即其繼承的抽象方法仍然是抽象的)稻艰;
5,子類實現(xiàn)父類的抽象方法的時候侈净,其形參也應(yīng)該跟父類保持一致尊勿,其訪問權(quán)限也不能更小畜侦;
——其原因其實這是“重寫現(xiàn)象”元扔,自然應(yīng)該遵循重寫的要求;
重載技術(shù)overloading
重載的基本概念
重載在“通常面向?qū)ο笳Z言”中的含義:
是指旋膳,在一個類(對象)中澎语,有多個名字相同但形參不同的方法的現(xiàn)象;
類似這樣:
class C{
function f1(){验懊。擅羞。。}
function f1($p1){鲁森。祟滴。。}
function f1($p1, $p2 ){歌溉。垄懂。。}
}
$c1 = new C();
$c1->f1();
$c1->f1(2);
$c1->f1(3,4);
重載在“php語言”中的含義:
是指痛垛,當(dāng)對一個對象或類使用其未定義的屬性或方法的時候草慧,其中的一些“處理機制”;
比如:
class A{
public $p1 = 1;
}
$a1 = new A();
echo $a1->p1; //1匙头;
echo $a1->p2; //出錯漫谷,未定義的屬性!
則:php中的重載技術(shù)蹂析,就是來應(yīng)對上述“出錯”的情況舔示,使代碼不出錯,而且還能“優(yōu)雅處理”电抚;
class A{
public $p = 1;
}
$a = new A();
echo $a->p; //1
echo $a->p2; //報錯
//處理
class A{
public $p = 1;
function __get($pro_name){
echo "調(diào)用了未定義字段"
}
}
$a = new A();
echo $a->p; //1
echo $a->p2; //不報錯,直接調(diào)用方法->調(diào)用了未定義字段
屬性重載
就是對一個對象的不存在的屬性進行使用的時候惕稻,這個類中預(yù)先設(shè)定好的應(yīng)對辦法(處理機制);
屬性蝙叛,本質(zhì)俺祠,就是變量,其只有4個操作:
取值:
當(dāng)對一個對象的不存在的屬性進行“取值”的時候,就會自動調(diào)用內(nèi)部方法:__GET()
賦值:
當(dāng)對一個對象的不存在的屬性進行“賦值”的時候蜘渣,就會自動調(diào)用內(nèi)部方法:__SET()
判斷(isset):
當(dāng)對一個對象的不存在的屬性進行isset()判斷的時候淌铐,就會自動調(diào)用內(nèi)部方法:__isset()
銷毀(unset):
當(dāng)對一個對象的不存在的屬性進行unset()銷毀的時候,就會自動調(diào)用內(nèi)部方法:__unset()
以上蔫缸,4個方法腿准,被稱為“魔術(shù)方法”;
__GET($屬性名):
在對一個對象的不存儲的屬性進行“取值”的時候捂龄,會自動調(diào)用的方法释涛;
我們其實是可以使用該方法來對這種“意外”情況進行某種特別的處理。
其中倦沧,該方法可以帶一個形參唇撬,表示這個要對之取值的不存在的屬性名(字符串);
__SET($屬性名展融,值):
當(dāng)對一個對象的不存在的屬性進行“賦值”的時候窖认,就會自動調(diào)用這個內(nèi)部的魔術(shù)方法;
它有2個形參告希,分別代表要對不存在的屬性進行賦值的時候的“屬性名”和“屬性值”扑浸;
這個方法,結(jié)合__GET方法燕偶,往往可以使我們定義的類喝噪,就有一種“可方便擴展屬性”的特性加缘。
即:類(或?qū)ο螅┑膶傩栽镒玻梢愿鼮榉奖阕杂桑?
class A{
protected $prop_list = array();
function __set($p,$v){
$this->prop_list[$p] = $v;
}
function __get($p){
return $this->prop_list[$p];
}
}
__ISSET($屬性名):
當(dāng)對一個對象的不存在的屬性進行isset()判斷的時候,就會自動調(diào)用內(nèi)部方法:__isset()值漫;
用法:
$v1 = isset($對象 -> 不存在的屬性); // 此時就會調(diào)用這個對象的所屬類中的魔術(shù)方法:__isset()
function __isset($prop){
$v = isset($this->prop_list[$prop]);
return $v;
}
__UNSET($屬性名):
當(dāng)對一個對象的不存在的屬性進行unset()銷毀操作的時候伯诬,就會自動調(diào)用內(nèi)部方法:__unset()
function __unset($prop){
unset($this->prop_list[$prop]);
}
方法重載
當(dāng)對一個對象的不存在的實例方法進行“調(diào)用”的時候晚唇,會自動調(diào)用類中的__call()這個魔術(shù)方法;
當(dāng)對一個類的不存在的靜態(tài)方法進行“調(diào)用”的時候盗似,會自動調(diào)用類中的__callstatic()這個靜態(tài)魔術(shù)方法哩陕;
class A{
function __call($method,$args){
echo "__call被調(diào)用了!"
}
}
利用php的重載技術(shù),實現(xiàn)通常的“方法重載”
什么是接口赫舒?
先看抽象類:
abstract class 類名 {
屬性1悍及;
屬性2;
.....
非抽象方法1接癌;
非抽象方法2心赶;
......
抽象方法1;
抽象方法2扔涧;
......
}
設(shè)想,將上述抽象類中“實在的成員”,刪除枯夜,即刪除那些非抽象的成員弯汰。則,自然該抽象類中湖雹,就只有抽象方法咏闪;
abstract class 類名 {
抽象方法1;
抽象方法2摔吏;
......
}
由此鸽嫂,可以理解為:這個抽象類,“太抽象了”征讲,幾乎自己什么都沒做据某,就光讓別人做什么。
那么:
接口就是這樣一個“天然不實在”的家伙:
接口诗箍,就是規(guī)定癣籽,里面只能放“抽象方法”和“常量”的一種類似類的語法結(jié)構(gòu);
——可見滤祖,接口就是“比抽象類更抽象的”一種語法結(jié)構(gòu)筷狼。
接口(interface)定義形式:
interface 接口名{
常量1;
常量2匠童;
.....
抽象方法1埂材;
抽象方法2;
.....
}
說明:
1汤求,可見俏险,接口中,只有常量(接口常量)和抽象方法兩種成員首昔;
2寡喝,接口常量的使用形式為: 接口名稱::常量名稱;
3勒奇,接口中的抽象方法预鬓,不要使用abstract修飾,也不需要使用訪問控制修飾符赊颠,因為其天然就是public
為什么需要接口格二?
面向?qū)ο缶幊趟枷胧菍Α艾F(xiàn)實世界”的描述(模擬)!
現(xiàn)實世界往往都都是多繼承的竣蹦;
但:
出于降低類跟類之間關(guān)系的復(fù)雜度的考慮顶猜,就將語言設(shè)計為單繼承的;
但這樣痘括,就無法表達出現(xiàn)實世界的多繼承特性长窄;
則:
接口就是對沒有多繼承的類之間關(guān)系的一個補充滔吠;
因為:接口可以實現(xiàn)“多繼承”——但此時不稱為繼承而已,而是稱為“實現(xiàn)”挠日;
即:
接口1 -->> 類1疮绷;
就稱為:類1實現(xiàn)了接口1;
其本質(zhì)嚣潜,其實就是類1中冬骚,有了接口1中“特征信息”;
使用形式:
形式為:
class 類名 implements 接口名1懂算, 接口名2只冻, ....{
//類的定義。
}
這里计技,叫做喜德,類實現(xiàn)了接口。
其中酸役,接口跟接口之間住诸,也可以繼承,跟類之間的繼承:
interface 接口1 extends 接口2{
//接口的成員定義涣澡;贱呐。。入桂。奄薇。
}
進一步完善mysqldb工具類:
完善分2個方面:
1,現(xiàn)有已經(jīng)完成的功能抗愁,做優(yōu)化處理馁蒂;
2,添加更多的功能蜘腌,要求繼續(xù)實現(xiàn)如下功能:
2.1:用該類的對象可以執(zhí)行任意的增刪改語句沫屡,并返回布爾值;
2.2:用該類的對象可以執(zhí)行返回一行數(shù)據(jù)的“查詢語句”:結(jié)果是一個一維數(shù)組撮珠,類似這樣:
array( ‘id’=>3, ‘name’=>’張三’, ‘a(chǎn)ge’ => 18, ‘edu’=>’大學(xué)’ );
2.3:用該類的對象可以執(zhí)行返回多行數(shù)據(jù)的“查詢語句”:結(jié)果是一個二維數(shù)組沮脖,類似這樣:
array(
0=>array( ‘id’=>3, ‘name’=>’張三’, ‘a(chǎn)ge’ => 18, ‘edu’=>’大學(xué)’ ),
1=>array( ‘id’=>4, ‘name’=>’張四’, ‘a(chǎn)ge’ => 14, ‘edu’=>’中學(xué)’ )芯急,
2=>array( ‘id’=>7, ‘name’=>’張七’, ‘a(chǎn)ge’ => 17, ‘edu’=>’小學(xué)’ )
)
2.4:用該類的對象可以執(zhí)行返回一個數(shù)據(jù)的“查詢語句”:結(jié)果是一個數(shù)據(jù)值勺届,其sql語句常常類似這樣: select name from Users where id = 1; 或: select count(*) as c from 表名;
含義:
當(dāng)某行代碼需要一個類的時候娶耍,php的內(nèi)部機制可以做到“自動加載該類文件”免姿,以滿足該行需要一個類的這種需求。
什么時候需要一個類榕酒?
1胚膊,new一個對象的時候故俐;
2,使用一個類的靜態(tài)方法的時候紊婉;
3购披,定義一個類(B)并以另一個類(A)作為父類的時候;
function __autoload($name){
require_once './'.$name.'.class.php'
}
$config = array(
"host"=>"localhost",
"port"=>3306,
"username"=>"root",
"password"=>"aaa",
"charset"=>"utf8",
"dbname"=>"db123"
);
$db = MySQLDB::ShareInstance($config);
條件和要求
1肩榕, 當(dāng)需要一個類的時候,就會自動調(diào)用某個函數(shù)(默認(rèn)是__autoload)惩妇,并傳入所需要的類的名字
2株汉, 一個類應(yīng)該保存到一個獨立的“類文件中”:即其中只有該類的定義,沒有別的代碼歌殃;
3,習(xí)慣上氓皱,類文件的命名要有一定的“規(guī)則”路召,通常是:類名.class.php
4波材,通常股淡,我們需要將各種類,存儲在一些特定的目錄中廷区,以方便確定其位置唯灵!
5,在該自動加載的函數(shù)中隙轻,“充分”使用傳過來的類名埠帕,以構(gòu)建一個合適的文件路徑并載入;
自定義自動加載函數(shù):
剛才玖绿,__autoload()函數(shù)敛瓷,是系統(tǒng)內(nèi)部的自動加載函數(shù),我們只是定義其函數(shù)體斑匪。
但:
我們可以使用更多函數(shù)(自定義的)呐籽,來實現(xiàn)更靈活的自動加載!
基本模式為:
spl_autoload_register(“函數(shù)1”); //聲明“函數(shù)1”作為自動加載函數(shù)秤标;
spl_autoload_register(“函數(shù)2”); //聲明“函數(shù)2”也作為自動加載函數(shù)绝淡;
.........
然后,就去定義這些函數(shù)苍姜,跟定義__autoload()函數(shù)一樣:
function 函數(shù)1( $class_name ){
//.......
}
function 函數(shù)2( $class_name ){
//.......
}
.............
這樣牢酵,系統(tǒng)就會一次調(diào)用這些自動加載函數(shù)去加載所需要的類,直到加載成功衙猪!
spl_autoload_register("autoload1");
spl_autoload_register("autoload2");
function autoload1($class_name){
$file = './class/'.$class_name.".class.php";
if(file_exists($file)){
include_once $file;
}
}
function autoload2($class_name){
$file = './lib/'.$class_name.".class.php";
if(file_exists($file)){
include_once $file;
}
}
對象的復(fù)制(克骡梢摇)
$obj1 = new A();
$obj1->p1 = 11;
$obj2 = $obj1; //值傳遞
//則布近,現(xiàn)在有幾個對象?——1個對象丝格!
當(dāng)然:
$obj3 = & $obj1;
結(jié)果撑瞧,還是一個對象!
對象的克隆語法显蝌,就是用于將一個對象“制作”雙份的語法预伺,類似之前普通數(shù)據(jù)的“值傳遞”;
語法:
$obj2 = clone $obj1; //這樣曼尊,就有一個跟$obj1完全一樣的新的對象酬诀。
對象的遍歷
對象的遍歷,跟數(shù)組的遍歷骆撇,一樣瞒御!
其實,只能遍歷出對象的“實例屬性數(shù)據(jù)”
foreach( $對象名 as $key => $value){
//這里就可以處理$key和$value
//但注意:
1, $key表示的是對象 的 “屬性”神郊,$value是其對應(yīng)值肴裙;
2, 這里能夠遍歷出來的屬性,只能是在該范圍中的“可訪問屬性”(就是要考慮訪問控制權(quán)限)
}
將一個對象的所有屬性都遍歷出來
class A{
public $p1 = 1;
protected $p2 = 2;
private $p3 = 3;
static $p4 = 4;
function showAllProperties(){
foreach($this as $key=>$vlue){
...
}
}
}
PHP內(nèi)置標(biāo)準(zhǔn)類
php語言內(nèi)部涌乳,有“很多現(xiàn)成的類”蜻懦,其中有一個,被稱為“內(nèi)置標(biāo)準(zhǔn)類”夕晓。
這個類“內(nèi)部”可以認(rèn)為什么都沒有阻肩,類似這樣:
class stdclass{ }
其作用,可以用于存儲一些臨時的簡單的數(shù)據(jù):
$obj1->pp1 = 1;
$obj1->port = ‘3306’;
也可以用于類型轉(zhuǎn)換時用于存儲數(shù)據(jù)运授,如下節(jié)所示
其他數(shù)據(jù)類型轉(zhuǎn)換為對象類型
其他數(shù)據(jù)類型轉(zhuǎn)換為對象類型烤惊,得到的結(jié)果是:內(nèi)置標(biāo)準(zhǔn)類(stdclass)的一個對象!
語法形式為:
$obj1 = (object) 其他類型數(shù)據(jù)吁朦;
? 數(shù)組轉(zhuǎn)換為對象:數(shù)組的鍵名當(dāng)作屬性名柒室,值為對應(yīng)值;
注意:數(shù)字下標(biāo)的數(shù)據(jù)元素逗宜,轉(zhuǎn)換為對象后的屬性雄右,無法通過對象語法獲取,因此不推薦轉(zhuǎn)換纺讲。
? null轉(zhuǎn)換為對象:空對象擂仍;
$obj1 = (object)null;
? 其他標(biāo)量數(shù)據(jù)轉(zhuǎn)換為對象:屬性名為固定的“scalar”,值為該變量的值:
類型約束
什么叫類型約束熬甚?
就是要求某個變量只能使用(接收逢渔,存儲)某種指定的數(shù)據(jù)類型;
php屬于“弱類型語言”乡括,通常不支持類型約束肃廓;
相應(yīng)的智厌,強類型語言,類型約束卻是其“基本特征”盲赊。
php中铣鹏,只支持局部的部分類型約束
php中,只支持在函數(shù)(或方法)的形參上哀蘑,設(shè)定類型的約束目標(biāo)诚卸,形式如下:
function 方法名(【要求使用的類型】$p1 , 【要求使用的類型】$p2, ..... ){
//..........
}
說明:
1,定義一個函數(shù)(方法)時绘迁, 一個形參惨险,可以使用類型約束,也可以不使用脊髓;
2,如果使用了類型約束栅受,則對應(yīng)的該實參數(shù)據(jù)将硝,就必須是要求的那種類型。
3屏镊,能夠使用的類型約束依疼,其實非常少,只有以下幾種可用:
數(shù)組: array而芥,
對象:使用類的名稱律罢,表示,傳遞過來的實參棍丐,必須是該類的實例误辑;
接口: 使用接口的名稱,表示歌逢,傳遞過來的實參巾钉,必須是實現(xiàn)了該接口的類的實例
單例類的加強:禁止克隆
對于一個類的對象,如果使用“clone運算符”秘案,就會克隆出一個跟當(dāng)前對象完全一樣的新對象出來砰苍,
并且:
此時還會自動調(diào)用該類中的魔術(shù)方法:_ _c l o n e ();只要其中有該方法阱高;
則赚导,要想實現(xiàn)單例類,就應(yīng)該對這個單例類的對象“禁止克隆”赤惊,做法是:
私有化這個魔術(shù)方法:_ _c l o n e ()吼旧;
與類有關(guān)的其他魔術(shù)方法
序列化與反序列化技術(shù)
含義:
序列化:
就是將一個變量所代表的“內(nèi)存”數(shù)據(jù),轉(zhuǎn)換為“字符串”形式并持久保存在硬盤上的一種做法未舟。
反序列化:
就是將序列化之后保存在硬盤上的“字符串?dāng)?shù)據(jù)”黍少,恢復(fù)為其原來的內(nèi)存形式的變量數(shù)據(jù)的一種做法寡夹。
序列化的做法:
$v1 = 123; //這是一個變量,代表任意的內(nèi)存數(shù)據(jù)
$s1 = serialize( $v1 ); //將任何類型的變量數(shù)據(jù)厂置,轉(zhuǎn)換為“字符串”
file_put_contents( ‘要保存的目標(biāo)文本文件’, $s1); //將該字符串菩掏,保存到一個文件里(就是硬盤數(shù)據(jù))
反序列化的做法:
$s1 = file_get_contents( ‘保存序列化數(shù)據(jù)的目標(biāo)文本文件’); //從一個文件里讀出其中的所有字符
$v1 = unserialize( $s1 ); //將該字符串?dāng)?shù)據(jù),反序列化轉(zhuǎn)換為變量(數(shù)據(jù))
__sleep():用于對象的序列化:
1昵济,對一個對象進行序列化智绸,只能將其屬性數(shù)據(jù)“保存起來”,而方法被忽略(方法不是數(shù)據(jù))
2访忿,對象的序列化的時候瞧栗,會自動調(diào)用該對象所屬類的這個魔術(shù)方法:__sleep()(前提是有該方法)。
且海铆,此時迹恐,該方法必須返回一個數(shù)組,數(shù)組中是“計劃”要進行序列化的屬性名卧斟;
__wakeup:用于對象的反序列化:
1殴边,對一個對象進行反序列化,其實是恢復(fù)其原來保存起來的屬性數(shù)據(jù)珍语,而且锤岸,此時必然需要依賴該對象原本的所屬類;
2板乙,對象在反序列化的時候是偷,會自動調(diào)用該對象所屬類的這個魔術(shù)方法:__wakeup()
__tostring()魔術(shù)方法——比較常用!
含義:
將一個對象“當(dāng)做”一個字符串來使用的時候募逞,會自動調(diào)用該方法蛋铆,并且在該方法中,可以返回一定的字符串放接,以表明該對象轉(zhuǎn)換為字符串之后的結(jié)果戒职。
注意:
如果沒有定義該方法,則對象無法當(dāng)做字符串來使用透乾!
__invoke()魔術(shù)方法:
將對象當(dāng)作函數(shù)來使用的時候洪燥,會自動調(diào)用該方法。通常不推薦這么做乳乌。
class A{
function __invoke(){
echo “<br />我是一個對象呀捧韵,你別當(dāng)我是一個函數(shù)來隨便調(diào)用!”;
}
}
$obj1 = new A();
$obj1(); //此時就會調(diào)用類中的方法:__invoke()
其他零碎:
與類有關(guān)的魔術(shù)常量:
以前學(xué)過的魔術(shù)常量:
__FILE__
__DIR__
__LINE__
現(xiàn)在:
__CLASS__: 代表當(dāng)前其所在的類的類名汉操;
__METHOD__:代表其當(dāng)前所在的方法名再来;
與類有關(guān)的系統(tǒng)函數(shù):
class_exists(“類名”), 判斷一個類是否存在(是否定義過)
interface_exists(“接口名”), 判斷一個接口是否存在(是否定義過)
get_class( $obj ), 獲得某個對象$obj 的所屬類
get_parent_class($obj ), 獲得某個對象$obj 的所屬類的父類
get_class_methods(), 獲得一個類的所有方法名,結(jié)果是一個數(shù)組,里面存儲的是這些方法的名稱
get_class_vars(), 獲得一個類的所有屬性名芒篷。結(jié)果是一個數(shù)組搜变,里面存儲的是這些屬性的名稱get_declared_classes() 獲得“整個系統(tǒng)”所定義的所有類名;
與對象有關(guān)的系統(tǒng)函數(shù):
is_object( $obj ): 判斷某個變量是否是一個對象针炉;
get_object_vars( $obj ):獲得一個對象的所有屬性挠他;結(jié)果是一個數(shù)組,里面存儲的是這些屬性的名稱
與類有關(guān)的運算符:
new篡帕,
instanceof: 判斷一個“變量”(對象殖侵,數(shù)據(jù)),是否是某個類的“實例”镰烧;
示意如下:
class A {}
class B {}
class C extends A{}
$a1 = new A();
$b1 = new B();
$c1 = new C();
$v1 = $a1 instanceof A ; //結(jié)果是true
$v2 = $b1 instanceof A ; //結(jié)果是false
$v3 = $c1 instanceof C ; //結(jié)果是true
$v4 = $c1 instanceof A ; //結(jié)果是true
——推論:一個類的對象拢军,必然也屬于這個類的上級類的對象;
static關(guān)鍵字的新用法和總結(jié):
static這個關(guān)鍵字怔鳖,也可以像“self”一樣茉唉,代表“當(dāng)前類”,用于訪問一個類的“靜態(tài)屬性或靜態(tài)方法”结执;
但度陆,
static,在應(yīng)用中昌犹,更靈活,因此更常見览芳!
因為static斜姥,它代表的是“調(diào)用”當(dāng)前方法的類,而不是“其代碼所在的類”:
self它就比較死板沧竟,只代表這個單詞本身所在位置的所在類铸敏。
面向?qū)ο缶幊趟枷氲?個特征:
封裝:
無非是一個大的指向思想,目的是為了將一個類設(shè)計得更為健壯悟泵!
其基本做法是:
盡可能地將一個類的成員私有化杈笔,只開放那些必不可少的對外的屬性或方法,能private的就不要protected糕非。能protected就不要public
繼承:
是面向?qū)ο蟮幕舅枷牒突咀龇ā?繼承是代碼重用的一種重要機制蒙具。
多態(tài):
多態(tài),就是“多種形態(tài)”朽肥,其實指的是禁筏,現(xiàn)實世界的“豐富多彩的表現(xiàn)形式”,比如:
人在吃飯衡招;
豬在吃食篱昔;
魚在進食;
小雞啄米;
州刽。空执。。穗椅。
他們都是“吃”這個行為辨绊!
在實際代碼(應(yīng)用)中,多態(tài)常常有兩種表現(xiàn)形式:
1房待, 不同對象邢羔,使用相同的方法,會表現(xiàn)為不同的結(jié)果桑孩!
2拜鹤, 同一個對象,使用相同的方法流椒,也可能會表現(xiàn)為不同的結(jié)果——這其實是“方法重載現(xiàn)象”