1.類與對象
對象:實際存在該類事物中每個實物的個體。$a =new User(); 實例化后的$a
引用:php的別名,兩個不同的變量名字指向相同的內容
封裝: 把對象的屬性和方法組織在一個類(邏輯單元)里
繼承:以原有的類為基礎,創建一個新類,從而代碼復用的目的;
多態:允許將子類類型的指針賦值給父類類型的指針。
-------------------------------------
2.自動加載對象:
?
自動加載通過定義特殊的__autoload函數,當引用沒有在腳本中定義的類時會自動調用這個函數.
- function?__autoload($class){??
- ??require_once("classes/$class.class.php");??
- }??
?
為什么要使用__autoload
1,首先是不知道這個類文件存放在什么地方,
2,另外一個就是不知道什么時候需要用到這個文件。
3,特別是項目文件特別多時,不可能每個文件都在開始的部分寫很長一串的 require …
替代了一
require_once ("classes/Books.class.php") ;?
require_once ("classes/Employees.class.php" ) ;?
require_once ("classes/Events.class.php") ;?
require_once ("classes/Patrons.class.php") ;
zend推薦了一種最流行的辦法,在文件名中包含路徑。例如下面的例子:
- view?sourceprint???
- //?Main.class????
- ??
- function?__autoload($class_name)?{?????
- ?????$path?=?str_replace('_',?DIRECTORY_SEPARATOR,?$class_name);?????
- ?????require_once?$path.'.php';?????
- ?}????
$temp = new Main_Super_Class();
所有的下劃線都會被替換成路徑中的分隔符,上例中就會去 Main/Super/Class.php文件。
缺點:
是在編碼過程中,必須明確的知道代碼文件應當所處的位置,
而且由于將文件路徑硬編碼在了類名中,如果需要修改文件夾的結構時,我們必須手工修改所有的類名。
如果是在一個開發環境中,并且對于速度不是很在意的話,使用'Include All’這個方法是非常方便的。
通過將所有類文件放在一個或幾個特定文件夾中,然后通過遍歷的方式查找加載。
例如
- <?php?????
- ??
- $arr?=?array?(?????
- ?????'Project/Classes',?????
- ????'Project/Classes/Children',?????
- ????'Project/Interfaces'????
- ?);????
- ??
- ?foreach($arr?as?$dir)?{?????
- ??
- ????$dir_list?=?opendir($dir);????
- ??
- ????while?($file?=?readdir($dir_list))?{?????
- ?????????$path?=?$dir.DIRECTORY_SEPARATOR.$file;?????
- ?????????if(in_array($file,?array('.',?'..'))?||?is_dir($path))?????
- ?????????????continue;????
- ?????????if?(strpos($file,?".class.php"))?????
- ?????????????require_once?$path;?????
- ?????}?????
- }?????
- ??
- ??>???
另外一個方法是在類文件和他的位置之間建立關聯的配置文件,例如:
- view?sourceprint???
- //?configuration.php?????
- ??
- array_of_associations?=?array(?????
- ????'MainSuperClass'?=?'C:/Main/Super/Class.php',?????
- ????'MainPoorClass'?=?'C:/blablabla/gy.php'????
- ?);???
調用的文件
- <?php?????
- ????require?'autoload_generated.php';????
- ????function?__autoload($className)?{?????
- ???????global?$autoload_list;?????
- ???????require_once?$autoload_list[$className];?????
- ????}????
- ??????$x?=?new?A();?????
- ?>???
------------------------------------------------
3.構造函數和析構函數
?
PHP 構造方法 __construct() 允許在實例化一個類之前先執行構造方法。
構造方法是類中的一個特殊方法。當使用 new 操作符創建一個類的實例時,構造方法將會自動調用,其名稱必須是 __construct() 。
(在一個類中只能聲明一個構造方法,而是只有在每次創建對象的時候都會去調用一次構造方法,不能主動的調用這個方法,
所以通常用它執行一些有用的初始化任務。該方法無返回值。)
作用: 用來創建對象時初始化對象
子類執行分類的構造函數parent::__construct().
析構函數: __destruct ()定義:特殊的內成員函數,沒有返回類型,沒有參數,不能隨意調用,也沒有重載;
??????? 只是在類對象生命結束的時候,由系統自動調用釋放在構造函數中分配的資源。
??與構造方法對應的就是析構方法,析構方法允許在銷毀一個類之前執行的一些操作或完成一些功能,比如說關閉文件、釋放結果集等。
??析構函數不能帶有任何參數,其名稱必須是 __destruct() 。?
作用:清理了善后工作,例如,在建立對象時使用new 開辟了一個內存空間,應在退出前使用析構函數釋放在構造函數中分配的資源。
例子:
- class?Person?{??
- ????public?$name;??
- ????public?$age;??
- ??
- ????//定義一個構造方法初始化賦值??
- ????public?function?__construct($name,$age)?{??
- ????????$this->name=$name;??
- ????????$this->age=$age;??
- ????}??
- ????public?function?say()?{??
- ????????echo?"my?name?is?:".$this->name."<br?/>";??
- ????????echo?"my?age?is?:".$this->age;??
- ????}??
- ????//析構函數??
- ????function?__destruct()??
- ????{??
- ????????echo?"goodbye?:".$this->name;??
- ????}??
- }??
- ??
- $p1=new?Person("ren",?25);??
- $p1->say();??
---------------------------------------------------------------
4 .訪問控制
對屬性或方法的訪問控制,是通過在前面添加關鍵字 public、protected 或 private 來實現的
?public 所定義的類成員可以在任何地方被訪問;
?protected 所定義的類成員則可以被其所在類的子類和父類訪問(當然,該成員所在的類也可以訪問);
?private 定義的類成員則只能被其所在類訪問。?
對類成員的訪問控制
?類成員都必須使用關鍵字public、protected 或 private 進行定義
對方法的訪問控制
類中的方法都必須使用關鍵字public、protected 或 private 進行定義。如果沒有設置這些關鍵字,則該方法會被設置成默認的 public。
例子:
- class?MyClass??
- {??
- ????public?$public?=?'Public';??
- ????protected?$protected?=?'Protected';??
- ????private?$private?=?'Private';??
- ??
- ????function?printHello()??
- ????{??
- ????????echo?$this->public;??
- ????????echo?$this->protected;??
- ????????echo?$this->private;??
- ????}??
- }??
- ??
- $obj?=?new?MyClass();??
- echo?$obj->public;?//?這行能被正常執行??
- echo?$obj->protected;?//?這行會產生一個致命錯誤??
- echo?$obj->private;?//?這行也會產生一個致命錯誤??
- $obj->printHello();?//?輸出?Public、Protected?和?Private??
-------------------------------------------------------------
5 .對象繼承
??? 繼承定義:以原有的類為基礎,創建一個新類,從而代碼復用的目的;
--------------------------------------
覆寫是對象繼承時用到的
重載是單對象中同方法名不同參數的方法
--------------------------------------
繼承已為大家所熟知的一個程序設計特性,PHP 的對象模型也使用了繼承。繼承將會影響到類與類,對象與對象之間的關系。
比如,當擴展一個類,子類就會繼承父類的所有公有和保護方法。但是子類的方法會覆蓋父類的方法。
繼承對于功能的設計和抽象是非常有用的,而且對于類似的對象增加新功能就無須重新再寫這些公用的功能。
?
- class?Person?{??
- ????public?$name;??
- ????public?$age;??
- ??
- ????function?say()?{??
- ????????echo?"my?name?is:".$this->name."<br?/>";??
- ????echo?"my?age?is:".$this->age;??
- ????}??
- }??
- ??
- //?類的繼承??
- class?Student?extends?Person?{??
- ????var?$school;????//學生所在學校的屬性??
- ??????
- ????function?study()?{??
- ????????echo?"my?name?is:".$this->name."<br?/>";??
- ????????echo?"my?shool?is:".$this->school;??
- ????}?????????
- }??
- ??
- $t1?=?new?Student();??
- $t1->name?=?"zhangsan";??
- $t1->school?=?"beijindaxue";??
- $t1->study();??
-------? ---------? ------?? ---------? --------?? -----
6 .范圍解析操作符(::)
?
范圍解析操作符(也可稱作 Paamayim Nekudotayim)或者更簡單地說是一對冒號,可以用于訪問靜態成員、方法和常量,還可以用于覆蓋類中的成員和方法。
當在類的外部訪問這些靜態成員、方法和常量時,必須使用類的名字。
self 和 parent 這兩個特殊的關鍵字是用于在類的內部對成員或方法進行訪問的。
注意:
當一個子類覆蓋其父類中的方法時,PHP 不會再執行父類中已被覆蓋的方法,直到子類中調用這些方法為止
例子:
- <?php??
- class?OtherClass?extends?MyClass??
- {??
- ????public?static?$my_static?=?'static?var';??
- ??
- ????public?static?function?doubleColon()?{??
- ????????echo?parent::CONST_VALUE?.?"\n";??
- ????????echo?self::$my_static?.?"\n";??
- ????}??
- }??
- ??
- OtherClass::doubleColon();??
- ?>???
---------------------------------------------------
7.Static關鍵字
聲明類成員或方法為static,就可以不實例化類而直接訪問。不能通過一個對象來訪問其中的靜態成員(靜態方法除外)。
靜態成員屬于類,不屬于任何對象實例,但類的對象實例都能共享。?
小結:
在類內部訪問靜態成員屬性或者方法,使用 self::(沒有 $ 符號),如:?
?self:: $country? //類內部訪問靜態成員屬性
?self:: myCountry()
在子類訪問父類靜態成員屬性或方法,使用 parent::(沒有 $ 符號),如:?
?parent:: $country
?parent:: myCountry()
外部訪問靜態成員屬性和方法為 類名/子類名:: ,如:?
?Person::$country
?Person::myCountry()
?Student::$country
但靜態方法也可以通過普通對象的方式訪問
?
- <?php??
- ??
- Class?Person{??
- ????//?定義靜態成員屬性??
- ????public?static?$country?=?"中國";??
- ????//?定義靜態成員方法??
- ????public?static?function?myCountry()?{??
- ????????//?內部訪問靜態成員屬性??
- ????????echo?"我是".self::$country."人<br?/>";??
- ????}??
- }??
- class?Student?extends?Person?{??
- ????function?study()?{??
- ????????echo?"我是".?parent::$country."人<br?/>";??
- ????}??
- }??
- //?輸出成員屬性值??
- echo?Person::$country."<br?/>";?????//?輸出:中國??
- $p1?=?new?Person();??
- //echo?$p1->country;????????????//?錯誤寫法??
- //?訪問靜態成員方法??
- Person::myCountry();????????????//?輸出:我是中國人??
- //?靜態方法也可通過對象訪問:??
- $p1->myCountry();??
- ??
- //?子類中輸出成員屬性值??
- echo?Student::$country."<br?/>";????//?輸出:中國??
- $t1?=?new?Student();??
- $t1->study();???????????//?輸出:我是中國人??
- ??
- ?>??
---------------------------------------------------
8.抽象類??? PHP5支持抽象類和抽象方法。
????? 抽象類不能直接被實例化,你必須先繼承該抽象類,然后再實例化子類。
????? 抽象類中 至少要包含一個抽象方法。如果類方法被聲明為抽象的,那么其中就不能包括具體的功能實現。?
????? 繼承一個抽象類的時候,子類必須實現抽象類中的所有抽象方法;
????? 另外,這些方法的可見性 必須和抽象類中一樣(或者更為寬松)。
????? 如果抽象類中某個抽象方法被聲明為protected,那么子類中實現的方法就應該聲明為protected或者public,而不 能定義為private。
????? //抽象方法:abstract protected function getValue();
例子1
- abstract?class?AbstractClass{??
- ????//?定義抽象方法??
- ????abstract?protected?function?getValue();??
- ????//?普通方法??
- ????public?function?printOut(){??
- ????????print?$this->getValue()."<br?/>";??
- ????}??
- }??
- class?ConcreteClass?extends?AbstractClass{??
- ????protected?function?getValue(){??
- ????????return?"abstract?";//抽象方法的實現??
- ????}??
- }??
- ??
- $class1?=?new?ConcreteClass;??
- $class1->printOut();??
例子2
??????
- abstract?class?AbstractClass??
- {??
- ?//?強制要求子類定義這些方法??
- ????abstract?protected?function?getValue();??
- ????abstract?protected?function?prefixValue($prefix);??
- ??
- ????//?普通方法(非抽象方法)??
- ????public?function?printOut()?{??
- ????????print?$this->getValue()?.?"\n";??
- ????}??
- }??
- ??
- class?ConcreteClass1?extends?AbstractClass??
- {??
- ????protected?function?getValue()?{??
- ????????return?"ConcreteClass1";??
- ????}??
- ??
- ????public?function?prefixValue($prefix)?{??
- ????????return?"{$prefix}ConcreteClass1";??
- ????}??
- }??
- ??
- class?ConcreteClass2?extends?AbstractClass??
- {??
- ????public?function?getValue()?{??
- ????????return?"ConcreteClass2";??
- ????}??
- ??
- ????public?function?prefixValue($prefix)?{??
- ????????return?"{$prefix}ConcreteClass2";??
- ????}??
- }??
- ??
- $class1?=?new?ConcreteClass1;??
- $class1->printOut();??
- echo?$class1->prefixValue('FOO_')?."\n";??
- ??
- $class2?=?new?ConcreteClass2;??
- $class2->printOut();??
- echo?$class2->prefixValue('FOO_')?."\n";??
/*
?* 抽象類不能直接被實例化,你必須先繼承該抽象類,然后再實例化子類。
????? 抽象類中 至少要包含一個抽象方法。如果類方法被聲明為抽象的,那么其中就不能包括具體的功能實現。?
????? 繼承一個抽象類的時候,子類必須實現抽象類中的所有抽象方法;
????? 另外,這些方法的可見性 必須和抽象類中一樣(或者更為寬松)。
????? 如果抽象類中某個抽象方法被聲明為protected,那么子類中實現的方法就應該聲明為protected或者public,而不 能定義為private。
?*?
?*/
- class?Person?{??
- ????public?$name;??
- ????public?$age;??
- ??
- ????function?say()?{??
- ????????echo?"my?name?is:".$this->name."<br?/>";??
- ????echo?"my?age?is:".$this->age;??
- ????}??
- }??
?
// 類的繼承
- class?Student?extends?Person?{??
- ????var?$school;????//學生所在學校的屬性??
- ??????
- ????function?study()?{??
- ????????echo?"my?name?is:".$this->name."<br?/>";??
- ????????echo?"my?shool?is:".$this->school;??
- ????}?????????
- }??
- ??
- $t1?=?new?Student();??
- $t1->name?=?"zhangsan";??
- $t1->school?=?"beijindaxue";??
- $t1->study();??
---------------------------------------------------------------------
9.接口
?接口定義:方法和常量值定義的集合
????????????? 通過interface來定義一個接口,就像定義一個標準的類一樣,但其中定義所有的方法都是空的。
????
?接口的特性:接口中定義的所有方法都必須是public
?
?接口的實現:一個接口可以使用implements操作符,類中必須實現接口中的所有方法,否則會報fatal錯誤,如果要實現多個接口,可以使用逗號來分隔多個接口的名稱。
抽象類和接口的區別
接口是特殊的抽象類,也可以看做是一個模型的規范。接口與抽象類大致區別如下:
1.一個子類如果 implements 一個接口,就必須實現接口中的所有方法(不管是否需要);如果是繼承一個抽象類,只需要實現需要的方法即可。
2.如果一個接口中定義的方法名改變了,那么所有實現此接口的子類需要同步更新方法名;而抽象類中如果方法名改變了,其子類對應的方法名將不受影響,只是變成了一個新的方法而已(相對老的方法實現)。
3.抽象類只能單繼承,當一個子類需要實現的功能需要繼承自多個父類時,就必須使用接口。?
實例1:
// 聲明一個'iTemplate'接口
- interface?iTemplate??
- {??
- ????public?function?setVariable($name,?$var);??
- ????public?function?getHtml($template);??
- }??
// 實現接口
// 下面的寫法是正確的
- class?Template?implements?iTemplate??
- {??
- ????private?$vars?=?array();??
- ????
- ????public?function?setVariable($name,?$var)??
- ????{??
- ????????$this->vars[$name]?=?$var;??
- ????}??
- ????
- ????public?function?getHtml($template)??
- ????{??
- ????????foreach($this->vars?as?$name?=>?$value)?{??
- ????????????$template?=?str_replace('{'?.?$name?.?'}',?$value,?$template);??
- ????????}??
- ???
- ????????return?$template;??
- ????}??
- }??
實例2:
//定義接口
- interface?User{??
- ?????function?getDiscount();??
- ?????function?getUserType();??
- ?}??
//VIP用戶 接口實現
- class?VipUser?implements?User{??
- ????//?VIP?用戶折扣系數??
- ????private?$discount?=?0.8;??
- ????function?getDiscount()?{??
- ????????return?$this->discount;??
- ????}??
- ????function?getUserType()?{??
- ????????return?"VIP?user";??
- ????}??
- }??
- class?Goods{??
- ????var?$price?=?100;??
- ????var?$vc;??
- ????//定義?User?接口類型參數,這時并不知道是什么用戶??
- ????function?run(User?$vc){??
- ????????$this->vc?=?$vc;??
- ????????$discount?=?$this->vc->getDiscount();??
- ????????$usertype?=?$this->vc->getUserType();??
- ????????echo?$usertype."goods?Price:".$this->price*$discount;??
- ????}??
- }??
- ??
- display?->run(new?VipUser);????//可以是更多其他用戶類型??
-------------------------------------------------------------
10.重載
?? 定義:一個類中的方法與另一個方法名稱相同,但參數不同
?? 什么情況下執行重載?? 當調用當前的環境下未被定義的屬性或者方法時,或者當調用當前環境下不可見的屬性或方法。
???
提示:
?如果父類定義方法時使用了 final 關鍵字,則不允許被子類方法覆蓋。
?訪問父類被覆蓋的方法
?可以通過parent:: 符號來訪問父類被覆蓋的方法或成員屬性:
?//PHP 重載方法 __call()
?__call()(Method overloading)
為了避免當調用的方法不存在時產生錯誤,可以使用 __call() 方法來避免。該方法在調用的方法不存在時會自動調用,程序仍會繼續執行下去。
語法:?
// __call()方法重載
- class?Test{??
- ????public?function?__call($name,$args){??
- ?????if($name==?'null'?&&?count($args)==2?){??
- ??????$type='num';??
- ???foreach($args?as?$key?=>?$val){??
- ???????if(!(is_int($val)?||?is_float($val))){??
- ????????$type=?'string';??
- ????}??
- ???}??
- ???$method=$name.ucfirst($type);??
- ???if(method_exists($this,$method),$args){??
- ???????call_user_func_array(array($this,$method),$args);??
- ???}??
- ??}??
- ?}??
- ?public?addNum($i,$j){??
- ?????echo?$i+$j;??
- ?}??
- ???
- ?public?addString($i,$j){??
- ?????echo?$i.$j;??
- ?}??
- }??
- $test?=new?Test();??
- $test->add(3,4);??
- $test->add(3,'4');??
- ???
案例:?
- class?MemberTest?{??
- ????????
- ????private?$data?=?array();//被重載的數據保存在此????
- ????public?$declared?=?1;/**??重載不能被用在已經定義的屬性??*/??
- ????private?$hidden?=?2;?/**??只有從類外部訪問這個屬性時,重載才會發生?*/??
- ??
- ????public?function?__set($name,?$value)?{??
- ????????echo?"Setting?'$name'?to?'$value'\n";??
- ????????$this->data[$name]?=?$value;??
- ????}??
- ??
- ????public?function?__get($name)?{??
- ????????echo?"Getting?'$name'\n";??
- ????????if?(array_key_exists($name,?$this->data))?{??
- ????????????return?$this->data[$name];??
- ????????}??
- ??
- ????????$trace?=?debug_backtrace();??
- ????????trigger_error(??
- ????????????'Undefined?property?via?__get():?'?.?$name?.??
- ????????????'?in?'?.?$trace[0]['file']?.??
- ????????????'?on?line?'?.?$trace[0]['line'],??
- ????????????E_USER_NOTICE);??
- ????????return?null;??
- ????}??
- ??
- ????/**??PHP?5.1.0之后版本?*/??
- ????public?function?__isset($name)?{??
- ????????echo?"Is?'$name'?set?\n";??
- ????????return?isset($this->data[$name]);??
- ????}??
- ??
- ????/**??PHP?5.1.0之后版本?*/??
- ????public?function?__unset($name)?{??
- ????????echo?"Unsetting?'$name'\n";??
- ????????unset($this->data[$name]);??
- ????}??
- ??
- ????/**??非魔術方法??*/??
- ????public?function?getHidden()?{??
- ????????return?$this->hidden;??
- ????}??
- }??
- ??
- ??
- echo?"<pre>\n";??
- ??
- $obj?=?new?MemberTest;??
- ??
- $obj->a?=?1;??
- echo?$obj->a?.?"\n\n";??
- ??
- var_dump(isset($obj->a));??
- unset($obj->a);??
- var_dump(isset($obj->a));??
- echo?"\n";??
- ??
- echo?$obj->declared?.?"\n\n";??
- ??
- echo?"Let's?experiment?with?the?private?property?named?'hidden':\n";??
- echo?"Privates?are?visible?inside?the?class,?so?__get()?not?used...\n";??
- echo?$obj->getHidden()?.?"\n";??
- echo?"Privates?not?visible?outside?of?class,?so?__get()?is?used...\n";??
- echo?$obj->hidden?.?"\n";??
//屬性重載:__set(),__get(),__isset(),__unset()
- class?Person{??
- ????private?$data?=array();??
- ????function?__set($name,$value){??
- ?????$this->data[$name]=$value;??
- ?}??
- ?function?__get($name){??
- ?????return?$this->data[$name];??
- ?}??
- }??
-----------------------------------------------------------------------------------
11.對象迭代
?????? PHP5提供了一種迭代(iteration)對象的功能,就像使用數組那樣,可以通過foreach 來遍歷對象中的屬性
???????
- class?MyClass??
- {??
- ????public?$var1?=?'value?1';??
- ????public?$var2?=?'value?2';??
- ????public?$var3?=?'value?3';??
- ??
- ????protected?$protected?=?'protected?var';??
- ????private???$private???=?'private?var';??
- ??
- ????function?iterateVisible()?{??
- ???????echo?"MyClass::iterateVisible:\n";??
- ???????foreach($this?as?$key?=>?$value)?{??
- ???????????print?"$key?=>?$value\n";??
- ???????}??
- ????}??
- }??
- ??
- $class?=?new?MyClass();??
- ??
- foreach($class?as?$key?=>?$value)?{??
- ????print?"$key?=>?$value\n";??
- }??
- echo?"\n";??
- ??
- ??
- $class->iterateVisible();??
---------------------------------------------------------------------------
12.設計模式: 工廠模式和 單例模式,?? 觀察者模式,命令鏈模式和策略模式
?
命令鏈 模式以松散耦合主題為基礎,發送消息、命令和請求,或通過一組處理程序發送任意內容。每個處理程序都會自行判斷自己能否處理請求。
如果可以,該請求被處理,進程停止。您可以為系統添加或移除處理程序,而不影響其他處理程序。
工廠模式
??? 定義:工廠模式(Factory)允許你在代碼執行時實例化對象。它之所以被稱為工廠模式是因為它負責“生產”對象。工廠方法的參數是你要生成的對象對應的類名稱。
?
工廠模式語法:
- <?php??
- class?Example??
- {??
- ????public?static?function?factory($type)??
- ????{??
- ????????if?(include_once?'Drivers/'?.?$type?.?'.php')?{??
- ????????????$classname?=?'Driver_'?.?$type;??
- ????????????return?new?$classname;??
- ????????}?else?{??
- ????????????throw?new?Exception?('Driver?not?found');??
- ????????}??
- ????}??
- }??
- ?>???
?? 工廠模式案例:
- <?php??
- interface?IUser{??
- ?function?getName();??
- }??
- class?User?implements?IUser{??
- ?public?function?__construct($id){}??
- ?public?function?getName(){??
- ?????return?"haha";??
- ?}??
- }??
- class?UserFactory{??
- ????public?static?function?Create($id){??
- ??return?new?User($id);??
- ?}??
- }??
- $uo?=UserFactory::Create(1);??
- echo?$uo->getName();??
- ??
- ?>??
????
???
單例
?? 定義三要素:1,某個類只能有一個實例? 2,必須自行創建這個實例? 3,必須自行向系統提供這個實例
???
?? 作用: 1,如果系統中需要有一個類來全局控制某些配置信息,那么使用單例模式可以很方便的實現。
????????? 2,使用單例模式,可以避免大量的new操作消耗資源()?
????????? 3在一個頁面請求中,便于調試,因為所有的代碼都集中在一個類中(如數據庫操作類) 可以在類中設置鉤子,輸出日志,從而避免到處都是var_dump
?????
單例模式(Singleton)用于為一個類生成一個唯一的對象。最常用的地方是數據庫連接。 使用單例模式生成一個對象后,該對象可以被其它眾多對象所使用。?
單件模式是我們在開發中經常用到的一種設計模式,利用PHP5面向對象的特性,我們可以很容易的構建單件模式的應用,下面是單件模式在PHP中的幾種實現方法:
- class?Stat{??
- ????static?$instance?=?NULL;??
- ??????
- ????static?function?getInstance(){??
- ????????if(self::$instance?==?NULL){??
- ????????????self::$instance?=?new?Stat();??
- ????????}??
- ??????????
- ????????return?self::$instance;??
- ????}??????
- ????private?function?__construct(){??
- ????}??????
- ????private?function?__clone(){??
- ????}??????
- ??????
- ????function?sayHi(){??
- ????????return?"The?Class?is?saying?hi?to?u?";??
- ????}??
- }??
- ??
- ??
- echo?Stat::getInstance()->sayHi();???
?
這是一種最通常的方式,在一個getInstance方法中返回唯一的類實例。
對這里例子稍加修改,便可以產生一個通用的方法,只要叫道任何你想用到單件的類里,就可以了。
- class?Teacher{??
- ????function?sayHi(){??
- ????????return?"The?teacher?smiling?and?said?'Hello?'";??
- ????}??
- ??????
- ????static?function?getInstance(){??
- ????????static?$instance;??
- ??????????
- ????????if(!isset($instance)){??
- ????????????$c?=?__CLASS__;??
- ????????????$instance?=?new?$c;??
- ????????}??????????
- ????????return?$instance;??
- ????}??
- }??
- ??
- echo?Teacher::getInstance()->sayHi();???
最后一種是提供一個singleton類,然后通過調用getInstance方法,可以為任何一個類生產出一個實例來。
- class?singleton{??
- ????function?getInstance($class){??
- ????????static?$instances?=?array();??
- ????????if(!array_key_exists($class,$instances)){??
- ????????????$instances[$class]?=?&new?$class;??
- ????????}??
- ????????$instance?=?$instances[$class];??
- ??????????
- ????????return?$instance;??
- ????}??
- }??
- ??
- class?People{??
- ????function?sayHi(){??
- ????????return?'Hello?i?am?a?people?';??
- ????}??
- }??
- ??
- echo?"<br?/>";??
- echo?singleton::getInstance('People')->sayHi();???
通過這三種方法,我們可以很容易的應用單件模式,如果能夠結合工廠模式,將使我們的編程變得更有條理和效率。
---------------------------------------------------------------------------------------
13.魔術方法
? 定義:PHP把所有以__(兩個下劃線)開頭的類方法當成魔術方法
??
? __construct, __destruct (參看 構造方法和析構方法),
? __call, __callStatic, __get, __set, __isset, __unset (參看 重載),?
? __sleep, __wakeup, __toString, __set_state 和 __clone 等方法在PHP中被稱為“魔術方法”(Magic methods)。
? 你在命名自己的類方法時不能使用這些方法名。
??
? serialize()?
? 作用: 第一. 在序列化之前,關閉對象可能具有的任何數據庫連接等.?
??????? 第二. 指定對象中需要被序列化的成員屬性,如果某個屬性比較大而不需要儲存下來,可以不把它寫進__sleep要返回的數組中,這樣該屬性就不會被序列化
??
? 在用serialize序列化對象時,會自動調用__sleep方法,__sleep方法必須返回一個數組,包含需要串行化的屬性。?
?????? PHP會拋棄其它屬性的值, 如果沒有__sleep方法,PHP將保存所有屬性,包括private屬性。
? unserialize()? 從字節流中創建了一個對象之后,馬上檢查是否具有__wakeup 的函數的存在。
? 如果存在,__wakeup 立刻被調用。使用 __wakeup 的目的是重建在序列化中可能丟失的任何數據庫連接以及處理其它重新初始化的任務。
?
下面給出一個序列化的代碼:共serialize.php和unserialize.php兩個文件。
?
- <?php??
- ???class?User???
- ???{???
- ???????public?$name;???
- ???????public?$id;??
- ??
- ???????function?__construct()???
- ???????{???
- ???????????$this->id?=?uniqid();??????????//give?user?a?unique?ID?賦予一個不同的ID???
- ???????}??
- ??
- ???????function?__sleep()???
- ???????{??????
- ???????????return(array("name"));????????//do?not?serialize?this->id?不串行化id??
- ???????}??
- ??
- ???????function?__wakeup()???
- ???????{???
- ???????????$this->id?=?uniqid();?????????//give?user?a?unique?ID???
- ???????}???
- ???}??
- ??
- ???$u?=?new?User;???
- ???$u->name?=?"HAHA";??
- ??
- ???$s?=?serialize($u);???????????????????//serialize?it?串行化?注意不串行化id屬性,id的值被拋棄??
- ??
- ???$u2?=?unserialize($s);????????????????//unserialize?it?反串行化?id被重新賦值??
- ??
- ?????
- ???//$u?and?$u2?have?different?IDs?$u和$u2有不同的ID???
- ???var_dump($u);???????????????????????????
- ???var_dump($u2);???
- ?>??
---------- PHP debug ----------
object(User)#1 (2) {
["name"]=>
string(4) "HAHA"
["id"]=>
string(13) "47fa045529f69"
}
object(User)#2 (2) {
["name"]=>
string(4) "HAHA"
["id"]=>
string(13) "47fa04552a49a"
}
---序列化--------反序列化--------------------
- class?ClassA?{??
- ????var?$int;??
- ????var?$str;??
- ????var?$bool;??
- ????var?$obj;??
- ????var?$pr;??
- }??
- ???
- $a?=?new?ClassA();??
- $a->int?=?1;??
- $a->str?=?"Hello";??
- $a->bool?=?false;??
- $a->obj?=?$a;??
- $a->pr?=?&$a->str;??
- ???
- echo?serialize($a);??
- //O:6:"ClassA":5:{s:3:"int";i:1;s:3:"str";s:5:"Hello";s:4:"bool";b:0;s:3:"obj";r:1;s:2:"pr";R:3;}??
- ????
? 在這個例子中,首先序列化的對象是 ClassA 的一個對象,那么給它編號為 1,接下來要序列化的是這個對象的幾個成員,第一個被序列化的成員是 int 字段,那它的編號就為 2,接下來被序列化的成員是 str,那它的編號就是 3,依此類推,到了 obj 成員時,它發現該成員已經被序列化了,并且編號為 1,因此它被序列化時,就被序列化成了 r:1; ,在接下來被序列化的是 pr 成員,它發現該成員實際上是指向 str 成員的一個引用,而 str 成員的編號為 3,因此,pr 就被序列化為 R:3; 了。
===============
//下面舉個簡單的例子,來說明 Serializable 接口的使用:序列化--------反序列化-
- class?MyClass?implements?Serializable??
- {??
- ????public?$member;??
- ???
- ????function?MyClass()??
- ????{??
- ????????$this->member?=?'member?value';??
- ????}??
- ???
- ????public?function?serialize()??
- ????{??
- ????????return?wddx_serialize_value($this->member);??
- ????}??
- ???
- ????public?function?unserialize($data)??
- ????{??
- ????????$this->member?=?wddx_deserialize($data);??
- ????}??
- }??
- $a?=?new?MyClass();??
- echo?serialize($a);??
- echo?"\n";??
- print_r(unserialize(serialize($a)));???
/*
輸出結果為(瀏覽器中的源代碼):
C:7:"MyClass":90:{<wddxPacket version='1.0'><header/><data><string>member value</string></data></wddxPacket>}
MyClass Object
(
??? [member] => member value
)?
因此如果想用其它語言來實現 PHP 序列化中的 C 標示的話,也需要提供一種這樣的機制,讓用戶自定義類時,
能夠自己在反序列化時處理 <data> 內容,否則,這些內容就無法被反序列化了。
*/
、、、、
? __sleep 和 __wakeup
serialize() 函數會檢查是否存在一個魔術方法 __sleep.如果存在,__sleep()方法會先被調用, 然后才執行序列化操作。這個功能可以用于清理對象,并返回一個包含對象中所有變量名稱的數組。如果該方法不返回任何內容,則NULL被序列化,導致 一個E_NOTICE錯誤。
__sleep方法常用于提交未提交的數據,或類似的操作。同時,如果你有一些很大的對象,不需要保存,這個功能就很好用。
與之相反,unserialize()會檢查是否存在一個__wakeup方法。如果存在,則會先調用 __wakeup方法,預先準備對象數據。
__wakeup經常用在反序列化操作中,否則是字符串;例如重新建立數據庫連接,或執行其它初始化操作
------------------------------------------------------------------------------------------------
?
14. Final關鍵字
??
? 如果父類中的方法被聲明為final,則子類無法覆蓋該方法; 如果一個類被聲明為final,則不能被繼承。
??
? 語法:
??
?類使用 final 關鍵字的例子:
?
- final?class?Person??
- ?{??
- ??......??
- ?}??
- ????
- ??class?BaseClass?{??
- ????public?function?test()?{??
- ?????echo?"BaseClass::test()?called\n";??
- ????}??
- ??????
- ????final?public?function?moreTesting()?{??
- ?????echo?"BaseClass::moreTesting()?called\n";??
- ????}??
- ?}??
- ??
- class?ChildClass?extends?BaseClass?{??
- ????public?function?moreTesting()?{??
- ???????echo?"ChildClass::moreTesting()?called\n";??
- ???}??
- }??
- ??
- ????
?
---------------------------------------------
15.對象復制
?
對象復制可以通過clone關鍵字來完成(如果對象中存在__clone()方法,會先被調用)。對象中的 __clone()方法不能直接調用。
?$copy_of_object = clone $object;
?
?
clone 關鍵字用于克隆一個完全一樣的對象,
__clone()??
?__clone() 方法來重寫原本的屬性和方法。是深復制
如果想在克隆后改變原對象的內容,需要在類中添加一個特殊的 __clone() 方法來重寫原本的屬性和方法。
?__clone() 方法只會在對象被克隆的時候自動調用。
clone 關鍵字用于克隆一個完全一樣的對象,__clone() 方法來重寫原本的屬性和方法。
對象克隆
有的時候我們需要在一個項目里面使用兩個或多個一樣的對象,如果使用 new 關鍵字重新創建對象,再賦值上相同的屬性,這樣做比較煩瑣而且也容易出錯。
PHP 提供了對象克隆功能,可以根據一個對象完全克隆出一個一模一樣的對象,而且克隆以后,兩個對象互不干擾。
使用關鍵字 clone 來克隆對象。語法: $object2 = clone $object;
例子1:?
2,
__clone()
如果想在克隆后改變原對象的內容,需要在類中添加一個特殊的 __clone() 方法來重寫原本的屬性和方法。
__clone() 方法只會在對象被克隆的時候自動調用。
?
//例子1:
- /*?
- class?Person?{?
- ????private?$name;?
- ????private?$age;?
- ?
- ????public?function?__construct($name,?$age)?{?
- ????????$this->name=$name;?
- ????????$this->age=$age;?
- ????}?
- ?
- ????public?function?say()?{?
- ????????echo?"my?name?is?:".$this->name."<br?/>";?
- ????????echo?"my?age?is?:".$this->age;?
- ????}?
- ????
- }?
- ?
- $p1?=?new?Person("haha",?20);?
- $p2?=?clone?$p1;?
- $p2->say();?
- */??
- class?Person?{??
- ????private?$name;??
- ????private?$age;??
- ??
- ????function?__construct($name,?$age)?{??
- ????????$this->name?=?$name;??
- ????????$this->age?=?$age;??
- ????}??
- ??
- ????function?say()?{??
- ????????echo?"my?name?is?:".$this->name."<br/>";??
- ????????echo?"?my?age?is?:".$this->age."<br?/>";??
- ????}??
- ????function?__clone()?{??
- ????????$this->name?=?"my?is?error?".$this->name;??
- ????????$this->age?=?30;??
- ????}??
- }??
- ??
- $p1?=?new?Person("haha",?20);??
- $p1->say();??
- $p2?=?clone?$p1;??
- $p2->say();??
- ??
- ???
?
------------------------------------------------------------------
16.對象比較
?
(==)? 如果兩個對象的屬性和屬性值 都相等,而且兩個對象是同一個類的實例,那么這兩個對象變量相等。
(===),這兩個對象變量一定要指向某個類的同一個實例(即同一個對象)。?
實例1
- class?A{??
- ??
- ??$a=new?A;??
- ??$b=new?A;???
- ???if($a==$b){??
- ??????echo?"true";??
- ???}else{??
- ??????echo?"false";??
- ???}??
- ??$c=new?A;??
- ??$d=&$c;??
- ??????if($c===$d){??
- ??????echo?"true";??
- ???}else{??
- ??????echo?"false";??
- ???}??
- ??
- }??
- ??
- 實例2??
- function?bool2str($bool)??
- {??
- ????if?($bool?===?false)?{??
- ????????return?'FALSE';??
- ????}?else?{??
- ????????return?'TRUE';??
- ????}??
- }??
- ??
- function?compareObjects(&$o1,?&$o2)??
- {??
- ????echo?'o1?==?o2?:?'?.?bool2str($o1?==?$o2)?.?"\n";??
- ????echo?'o1?!=?o2?:?'?.?bool2str($o1?!=?$o2)?.?"\n";??
- ????echo?'o1?===?o2?:?'?.?bool2str($o1?===?$o2)?.?"\n";??
- ????echo?'o1?!==?o2?:?'?.?bool2str($o1?!==?$o2)?.?"\n";??
- }??
- ??
- class?Flag??
- {??
- ????public?$flag;??
- ??
- ????function?Flag($flag?=?true)?{??
- ????????$this->flag?=?$flag;??
- ????}??
- }??
- ??
- class?OtherFlag??
- {??
- ????public?$flag;??
- ??
- ????function?OtherFlag($flag?=?true)?{??
- ????????$this->flag?=?$flag;??
- ????}??
- }??
- ??
- $o?=?new?Flag();??
- $p?=?new?Flag();??
- $q?=?$o;??
- $r?=?new?OtherFlag();??
- ??
- echo?"Two?instances?of?the?same?class\n";??
- compareObjects($o,?$p);??
- ??
- echo?"\nTwo?references?to?the?same?instance\n";??
- compareObjects($o,?$q);??
- ??
- echo?"\nInstances?of?two?different?classes\n";??
- compareObjects($o,?$r);??
-----------------------------------------
17.對象和引用
? 引用:php的引用是別名,就是兩個不同的變量名字指向相同的內容
?
- class?A?{??
- ????public?$foo?=?1;??
- }????
- ??
- $a?=?new?A;??
- $b?=?$a;?????//?$a?,$b都是同一個標識符的拷貝??
- ?????????????//?($a)?=?($b)?=?<id>??????
- $b->foo?=?2;??
- echo?$a->foo."\n";??
- ??
- ??
- $c?=?new?A;??
- $d?=?&$c;????//?$c?,$d是引用??
- ?????????????//?($c,$d)?=?<id>??
- ??
- $d->foo?=?2;??
- echo?$c->foo."\n";??
- ??
- ??
- $e?=?new?A;??
- ??
- function?foo($obj)?{??
- ????//?($obj)?=?($e)?=?<id>??
- ????$obj->foo?=?2;??
- }??
- ??
- foo($e);??
- echo?$e->foo."\n";??
-------------------------------------------------------------------------------
對象序列化
序列化對象 - 在會話中存放對象
所有php里面的值都可以使用函數serialize()來返回一個包含字節流的字符串來表示。
unserialize()函數能夠重新把字符串變回php原來的值。
序列化一個對象將會保存對象的所有變量,但是不會保存對象的方法,只會保存類的名字。?
為了能夠unserialize()一個對象,這個對象的類必須已經定義過。
如果序列化類A的一個對象,將會返回一個跟類A相關,而且包含了對象所有變量值的字符串。?
如果要想在另外一個文件中解序列化一個對象,這個對象的類必須在解序列化之前定義,可以通過包含一個定義該類的文件或使用函數spl_autoload_register()來實現
實例1:
- class?A?{??
- ??????public?$one?=?1;??
- ??????
- ??????public?function?show_one()?{??
- ??????????echo?$this->one;??
- ??????}??
- ??}??
- ????
- //?page1.php:??
- ??
- ??include("classa.inc");??
- ????
- ??$a?=?new?A;??
- ??$s?=?serialize($a);??
? // 把變量$s保存起來以便文件page2.php能夠讀到
? file_put_contents('store', $s);
// page2.php:
??
? // 要正確了解序列化,必須包含下面一個文件
? include("classa.inc");
? $s = file_get_contents('store');
? $a = unserialize($s);
? // 現在可以使用對象$a里面的函數 show_one()
? $a->show_one();
------------------------------------
后期靜態綁定)
???? 后期綁定“的意思是說,static::不再被解析為定義當前方法所在的類,而是在實際運行時計算的。也可以稱之為”靜態綁定“,因為它可以用于(但不限于)靜態方法的調用
???? 后期靜態綁定的功能:用于在繼承范圍內引用靜態調用的類。
self:: 的限制
使用self:: 或者 __CLASS__對當前類的靜態引用,取決于定義當前方法所在的類:
實例1:
- <?php??
- class?A?{??
- ????public?static?function?who()?{??
- ????????echo?__CLASS__;??
- ????}??
- ????public?static?function?test()?{??
- ????????self::who();??
- ????}??
- }??
- ??
- class?B?extends?A?{??
- ????public?static?function?who()?{??
- ????????echo?__CLASS__;??
- ????}??
- }??
- ??
- B::test();??
- ?>???
?
------------------------------------------------------------------------------------------
18.$this關鍵字
????????? $this 的含義是表示 實例化后的 具體對象!
??????????
??? this的用法:
??? 1,this是指向對象實例的一個指針,self是對類本身的一個引用,parent是對父類的引用。
??? 1,類的內部使用:如果從類的內部訪問不為常量const或者static變量或者方法,那么就必須使用自引用的$this
??? 2,在構造函數中 指該構造函數創建新對象
??? 3,引用$this,代表當前的類,解決變量命名沖突和不確定性問題\
????
??? --------------------------------
?
- class?Test{??
- ?function?__call($name,$args){??
- ??if($name=='add'?&&?count($args)==2){??
- ???$type='num';??
- ??}??
- ??foreach?($args?as?$key=>$val){??
- ???if(!is_int($val)?||?is_float($val)){??
- ????$type='string';??
- ???}??
- ??}??
- ??$method=$name.ucfirst($type);??
- ????
- ??if(method_exists($this,$method)){??
- ???call_user_func_array(array($this,$method),$args);??
- ??}??
- ?}??
- ?function?addNum(){??
- ??echo?$i+$j;??
- ?}??
- ?function?addString(){??
- ??echo?$i.$j;??
- ?}??
- }??
- $test?=?new?Test();??
- $test->add(3,5);??
- $test->add(4,'4');??
----------------------------------------------
/*
?* 常量 const
在類里面定義常量用 const 關鍵字,而不是通常的 define() 函數。?
語法: const constant = "value";
例子:?
運行該例子輸出:?
?中國
?我是中國人
?*?
?*/
- Class?Person{??
- ????//?定義常量??
- ????const?COUNTRY?=?"china";??
- ????public?function?myCountry()?{??
- ????????//內部訪問常量??
- ????????echo?"my?is?".self::COUNTRY."?person<br?/>";??
- ????}??
- }??
- //?輸出常量??
- echo?Person::COUNTRY."<br?/>";??
- //?訪問方法??
- $p1?=?new?Person();??
- $p1?->?myCountry();??
- Person::myCountry();??
--------------------
/*
?* PHP 對象的存儲與傳輸(序列化 serialize 對象)
對象的存儲與傳輸
在實際項目應用中,有些任務在一兩個頁面是無法完成的,由于變量到腳本執行完畢就釋放,我們本頁所生成的對象想在其它頁面使用時便碰到了麻煩。
如果需要將對象及其方法傳遞到我們想使用對象的頁面,比較簡單可行的辦法是將對象序列化后存儲起來或直接傳輸給需要的頁面,另一種辦法是將對象注冊為 session 變量。
序列化對象
對象序列化,就是將對象轉換成可以存儲的字節流。當我們需要把一個對象在網絡中傳輸時或者要把對象寫入文件或是數據庫時,就需要將對象進行序列化。
序列化完整過程包括兩個步驟:一個是序列化,就是把對象轉化為二進制的字符串,serialize() 函數用于序列化一個對象;另一個是反序列化,就是把對象被序列轉化的二進制字符串再轉化為對象,unserialize() 函數來反序列化一個被序列化的對象。這樣整個過程下來,對象內的類型結構及數據都是完整的。
語法:
string serialize( mixed value )
mixed unserialize( string str [, string callback] )
?*?
?*/
- class?Person?{??
- ????private?$name;??
- ????private?$age;??
- ??
- ????function?__construct($name,?$age)?{??
- ????????$this->name?=?$name;??
- ????????$this->age?=?$age;??
- ????}??
- ??
- ????function?say()?{??
- ????echo?"my?name?is?".$this->name."<br?/>";??
- ????echo?"?my?age?is?".$this->age;??
- ????}??
- }??
- ??
- $p1?=?new?Person("haha",?20);??
- $p1_string?=?serialize($p1);??
- ??
- //將對象序列化后寫入文件??
- $fh?=?fopen("p1.text",?"w");??
- fwrite($fh,?$p1_string);??
- fclose($fh);??
--------------
<?php
/*
?* PHP面向對象之this 關鍵字
1,PHP5中為解決變量的命名沖突和不確定性問題,引入關鍵字“$this”代表其所在當前對象。
2,$this在構造函數中指該構造函數所創建的新對象。
3,在類中使用當前對象的屬性和方法,必須使用$this->取值。方法內的局部變量,不屬于對象,不使用$this關鍵字取值。
局部變量和全局變量與 $this 關鍵字
4,使用當前對象的屬性必須使用$this關鍵字。
局部變量的只在當前對象的方法內有效,所以直接使用。
注意:局部變量和屬性可以同名,但用法不一樣。在使用中,要盡量避免這樣使用,以免混淆。
1234567891011121314 <!-- 驗證屬性和局部變量使用方法的類 -->?
- <?php???
- class?A{???????
- ????private?$a?=?99;?????//這里寫一個打印參數的方法.???????
- ????public?function?printInt($a){???????????
- ????????echo?"這里的?\$a?是傳遞的參數?$a?";???????????
- ????????echo?"<br>";???????????
- ????????echo?"這里的?\$this->a?是屬性?$this->a";???????
- ????}???
- }???
- ?$a?=?new?A();?//?這里的$a?可不是類中的任何一個變量了.???
- ?$a->printInt(88);??
- ?>???
運行結果:
12 這里的 $a 是傳遞的參數 88 這里的 $this->a 是屬性 99
用$this調用對象中的其它方法
1234567891011121314151617 <!--寫一個類,讓他自動完成最大值的換算.-->
?
- <?php???
- class?Math{?????//兩個數值比較大小.???????
- ????public?function?Max($a,$b){???????????
- ????????return?$a>$b?$a:$b;???????
- ????}?????//三個數值比較大小.???????
- ????public?function?Max3($a,$b,$c){?????????//調用類中的其它方法.??????????
- ?????????$a?=?$this->Max($a,$b);???????????
- ????????return?$this->Max($a,$c);???????
- ????}??
- }???
- $math?=?new?Math();???
- echo?"最大值是?".$math->Max3(99,100,88);???
- ?>???
?
運行結果:
1 最大值是 100
使用$this調用構造函數
調用構造函數和析構函數的方法一致。
12345678910111213141516
- <??class?A{???????
- private?$a?=?0;???????
- public?function?__construct(){???????????
- $this->a?=?$this->a?+?1?;???????
- }?????????
- public?function?doSomeThing(){???????????
- $this->__construct();???????????
- return?$this->a;???????
- }????????
- }???
- $a?=?new?A();???
- //?這里的$a?可不是類中的任何一個變量了.???
- echo?"現在?\$a?的值是"?.?$a->doSomeThing();???
- ?>??
?
運行結果:
1 現在 $a 的值是2
$this 到底指的什么?
$this 就是指當前對象,我們甚至可以返回這個對象使用 $this
12345678910111213
- <?php?class?A{???????
- public?function??getASelf(){???????????
- return?$this;???????
- }???????
- public?function?__toString(){???????????
- return?"這是類A的實例.";???????
- }???
- }???
- $a?=?new?A();???
- //?創建A的實例;???
- $b?=?$a->getASelf();???
- //調用方法返回當前實例.???
- echo?$a;???
- //打印對象會調用它的__toString方法.???
- ?>???
程序運行結果:
1 這是類A的實例.
通過 $this 傳遞對象
在這個例子中,我們寫一個根據不同的年齡發不同工資的類.
我們設置處理年齡和工資的業務模型為一個獨立的類.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
- <?php???
- class?User{???????
- private?$age?;???????
- private?$sal?;???????
- private?$payoff?;???
- //聲明全局屬性.?????????
- //構造函數,中創建Payoff的對象.???????
- public?function?__construct(){???????????
- $this->payoff?=?new?Payoff();???????
- }???????
- public?function?getAge(){???????????
- return?$this->age;???????
- }???????
- public?function?setAge($age){???????????
- $this->age?=?$age;???????
- }???????
- //?獲得工資.???????
- public??function?getSal(){???????????
- $this->sal?=????
- $this->payoff->figure($this);???????????
- return?$this->sal;???????
- }???
- }???
- //這是對應工資與年齡關系的類.???
- class?Payoff{???????
- public?function?figure($a){???????????
- $sal?=0;???????????
- $age?=?$a->getAge();???????????
- if($age?>80?||?$age?<16?){???????????????
- $sal?=?0;???????????
- }elseif?($age?>?50){???????????????
- $sal?=?1000;???????????
- }else{???????????????
- $sal?=?800;???????????
- }???????????
- return?$sal;???????
- }?}???
- //實例化User???
- $user?=?new?User();?????
- $user->setAge(55);???
- echo?$user->getAge()."age?,his?sal?is?"?.?$user->getSal();?echo?"<br>";?????
- $user->setAge(20);???
- echo?$user->getAge()."age?,?his?sal?is?"?.?$user->getSal();?echo?"<br>";?????
- $user->setAge(-20);?echo?$user->getAge()."age?,?his?sal?is?"?.?$user->getSal();?echo?"<br>";????
- $user->setAge(150);?echo?$user->getAge()."age?,?his?sal?is?"?.?$user->getSal();???
- ?>???
運行結果:
1234 55age ,his sal is 1000 20age , his sal is 800 -20age , his sal is 0 150age , his sal is 0.
**/