PHP-面向对象编程教程
1.2 面向對象介紹
1.2.1 介紹
面向對象是一個編程思想。編程思想有面向過程和面向對象
面向過程:編程思路集中的是過程上
面向對象:編程思路集中在參與的對象
以去飯館吃飯為例:
? 面向過程:點菜——做菜——上菜——吃飯——結賬——收拾
? 面向對象:服務員,廚師,客人
1.2.2 面向對象的好處
1.3 類和對象
1、對象是具體存在的事物,對象是由屬性(變量)和方法(函數)組成的
2、類是具有相同屬性和行為的一組對象的集合
分析:做菜動作——廚師對象——廚師類
結論:我們在開發的時候,先寫類,通過類創建對象,然后調用對象的屬性和方法實現功能。 類——對象——調用成員
注意:一個類可以創建多個對象
小結:
1、對象是由屬性和方法組成的
2、類是所有對象的相同屬性和方法的集合
3、在開發的時候先寫類,通過類創建對象,通過對象調用方法和屬性
4、一個類可以創建多個對象
?
1.4 在PHP中實現類和對象
1.4.1 創建類
語法:
class 類名{//屬性//方法//常量 } 類是由屬性、方法、常量組成的,也可以說 類成員有:屬性、方法、常量類名的命名規則:
1.4.2 對象實例化
通過new關鍵字來實例化對象。
<?php //定義類 class Student {} //實例化對象 $stu1=new Student(); $stu2=new Student; //小括號可以省略 var_dump($stu1,$stu2); //object(Student)#1 (0) { } object(Student)#2 (0) { }1.4.3 對象的比較
注意:對象的傳遞是地址傳遞
相等:結構和保存的值一樣就相等
全等:指向同一個對象才是全等。
1.5 屬性
屬性本質就是變量
通過->調用對象的成員 對象名->屬性名 對象名->方法名()
<?php //定義類 class Student {public $name; //屬性public $add='地址不詳'; //屬性 } //實例化對象 $stu=new Student(); //print_r($stu); //Student Object ( [name] => [add] => 地址不詳 ) //操作屬性 //1、給屬性賦值 $stu->name='tom'; $stu->add='北京';//2、獲取屬性的值 echo '姓名:'.$stu->name,'<br>'; //姓名:tom echo '地址:'.$stu->add,'<br>'; //地址:北京//3、添加屬性 $stu->age=20; print_r($stu); //Student Object ( [name] => tom [add] => 北京 [age] => 20 ) echo '<br>'; //4、刪除屬性 unset($stu->add); print_r($stu); //Student Object ( [name] => tom [age] => 20 )1.6 方法
方法的本質就是函數
<?php class Student {//定義方法public function show() {echo '這是show方法<br>';}//public可以省略,如果省略,默認就是publicfunction test() {echo '這是test方法<br>';} } $stu=new Student; $stu->show(); //調用方法 $stu->test();多學一招:
1、方法前面public是可以省略的,如果省略,默認就是public的。
2、屬性前面的public不能省略
1.7 訪問修飾符
用來控制成員的訪問權限
| public(公有的) | 在類的內部和外部都能訪問 |
| private(私有的) | 只能在類的內部訪問 |
| protected(受保護的) | 在整個繼承鏈上訪問 |
**多學一招:**一般來說,屬性都用私有的,通過公有的方法對私有的屬性進行賦值和取值。
作用:保證數據的合法性
<?php //訪問修飾符 class Student {private $name; //私有屬性private $sex; //私有屬性//通過公有的方法對私有的屬性進行賦值public function setInfo($name,$sex) {if($sex!='男' && $sex!='女'){echo '性別必須是男或女';exit;}$this->name=$name; //$this表示當前對象$this->sex=$sex;}//顯示信息public function getInfo() {echo '姓名:'.$this->name,'<br>';echo '性別:'.$this->sex,'<br>';} } //實例化 $stu=new Student; $stu->setInfo('tom','男'); $stu->getInfo(); echo '<hr>'; $stu2=new Student; $stu2->setInfo('berry','女'); $stu2->getInfo();提示:$this表示調用當前方法的對象
運行結果
1.8 類和對象在內存中的分布
分析如下代碼的結構
<?php class Student {public $name;public $sex;public function show() {} }$stu1=new Student; $stu2=new Student;$stu1->show();示意圖
1.9 封裝
封裝就是有選擇性的提供數據
通過訪問修飾符來實現封裝
1.10 構造方法
1.10.1 介紹
構造方法也叫構造函數,當實例化對象的時候自動執行。
語法:
例題
<?php class Student {public function __construct() {echo '這是構造方法<br>';} } new Student(); //這是構造方法 new Student(); //這是構造方法注意:在其他語言里,與類名同名的函數是構造函數,在PHP中不允許這種寫法。
class Student {//和類名同名的方法是構造方法,PHP中不建議使用public function Student() {echo '這是構造方法<br>';} } /* Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; Student has a deprecated constructor in F:\wamp\www\6-demo.php on line 2 這是構造方法 */1.10.2 構造函數作用:初始化成員變量
<?php class Student {private $name;private $sex;//構造函數初始化成員變量public function __construct($name,$sex) {$this->name=$name;$this->sex=$sex;}//顯示信息public function show() {echo "姓名:{$this->name}<br>";echo "性別:{$this->sex}<br>";} } //實例化 $stu=new Student('tom','男'); $stu->show(); //運行結果 /* 姓名:tom 性別:男 */注意:構造函數可以帶參數,但不能有return。
.11 析構方法
1.11.1 介紹
當對象銷毀的時候自動調用
語法
function __destruct(){ }腳下留心:析構函數不可以帶參數
例題
<?php class Student {private $name;//構造方法public function __construct($name) {$this->name=$name;echo "{$name}出生了<br>";}//析構方法public function __destruct() {echo "{$this->name}銷毀了<br>";} } //測試 $stu1=new Student('tom'); $stu2=new Student('berry'); $stu3=new Student('ketty'); echo '<hr>';運行結果
1.11.2 計算機的內存管理
計算機內存管理方式:先進先出,先進后出
先進先出的內存管理方式一般用在業務邏輯中,比如秒殺、購票等等
先進后出是計算機的默認內存管理方式
1.11.3 思考題
思考題1
<?php class Student {private $name;//構造方法public function __construct($name) {$this->name=$name;echo "{$name}出生了<br>";}//析構方法public function __destruct() {echo "{$this->name}銷毀了<br>";} } //測試 $stu1=new Student('tom'); $stu2=new Student('berry'); $stu3=new Student('ketty'); unset($stu2); echo '<hr>'; /* tom出生了 berry出生了 ketty出生了 berry銷毀了ketty銷毀了 tom銷毀了 */思考題2
<?php class Student {private $name;//構造方法public function __construct($name) {$this->name=$name;echo "{$name}出生了<br>";}//析構方法public function __destruct() {echo "{$this->name}銷毀了<br>";} } //測試 new Student('tom'); new Student('berry'); new Student('ketty'); /* tom出生了 tom銷毀了 berry出生了 berry銷毀了 ketty出生了 ketty銷毀了 */思考題3
<?php class Student {private $name;//構造方法public function __construct($name) {$this->name=$name;echo "{$name}出生了<br>";}//析構方法public function __destruct() {echo "{$this->name}銷毀了<br>";} } //測試 $stu=new Student('tom'); $stu=new Student('berry'); $stu=new Student('ketty'); /* tom出生了 berry出生了 tom銷毀了 ketty出生了 berry銷毀了 ketty銷毀了 */1.12 繼承
1.12.1 繼承介紹
語法
class 子類 extends 父類{ }例題
<?php //父類 class Person {public function show() {echo '這是人類<br>';} } //子類繼承父類 class Student extends Person { } //測試 $stu=new Student; $stu->show(); //這是人類執行過程:
第一步:在Student類中查找show(),如果找到就調用,找不到就到父類中查找
第二步:在Person類中查詢show()
1.12.2 子類中調用父類成員
<?php //父類 class Person {public function show() {echo '這是人類<br>';} } //子類 class Student extends Person {public function test() {//方法一;/*$person=new Person();$person->show(); //這是人類*///方法二$this->show(); //這是人類} } //測試 $stu=new Student; $stu->test();小結:
1、方法一:通過實例化父類調用父類的成員
2、方法二:通過$this關鍵字調用父類的成員
1.12.3 protected
protected:受保護的,在整個繼承鏈上使用
例題:
//例題一: <?php class A {protected $num=10; //在整個繼承鏈上訪問 } class B extends A { public function getNum() {echo $this->num;} } //測試 $obj=new B(); //整個繼承鏈上有A和B $obj->getNum(); //10//例題二: <?php class A {public function getNum() {echo $this->num;} } class B extends A {protected $num=10; } //測試 $obj=new B(); //整個繼承鏈上有A和B $obj->getNum(); //10//例題三: <?php class A {public function getNum() {echo $this->num;} } class B extends A {protected $num=10; } //測試 $obj=new A(); //整個繼承鏈上只有A $obj->getNum(); //Notice: Undefined property: A::$num1.12.4 繼承中的構造函數
規則:
1、如果子類有構造函數就調用子類的,如果子類沒有就調用父類的構造函數。2、子類的構造函數調用后,默認不再調用父類的構造函數通過類名調用父類的構造函數
類名::__construct()例題
<?php class Person {//父類的構造函數public function __construct() {echo '這是父類<br>';} } class Student extends Person {//子類的構造函數public function __construct() {Person::__construct(); //通過父類的名字調用父類的構造函數parent::__construct(); //parent表示父類的名字echo '這是子類<br>';} } //測試 new Student();注意:parent關鍵字表示父類的名字,可以降低程序的耦合性
例題:給父類傳遞參數
<?php class Person {protected $name;protected $sex;//父類的構造函數public function __construct($name,$sex) {$this->name=$name;$this->sex=$sex;} } class Student extends Person {private $score;//子類的構造函數public function __construct($name,$sex,$score) {parent::__construct($name,$sex); //調用父類構造函數并傳遞參數$this->score=$score;}//顯示信息public function getInfo() {echo "姓名:{$this->name}<br>";echo "性別:{$this->sex}<br>";echo "成績:{$this->score}";} } //測試 $stu=new Student('tom','男',88); $stu->getInfo(); /* 姓名:tom 性別:男 成績:88 */1.12.5 $this詳解
t h i s 表 示 當 前 對 象 的 引 用 , 也 就 是 是 或 this表示當前對象的引用,也就是是或this表示當前對象的引用,也就是是或this保存的當前對象的地址
<?php class A {public function __construct() {var_dump($this);} } class B extends A {} new A(); //object(A)#1 (0) { } echo '<br>'; new B(); //object(B)#1 (0) { }1.12.6 多重繼承
PHP不允許多重繼承,因為多重繼承容易產生二義性
如何實現C繼承A和B,使用繼承鏈
1.13?多態
多態:多種形態。
多態分為兩種:方法重寫和方法重載
1.13.1 方法重寫
子類重寫了父類的同名的方法
<?php //父類 class Person {public function show() {echo '這是父類<br>';} } //子類 class Student extends Person {//子類重寫了父類的同名方法public function show() {echo '這是子類<br>';} } //測試 $stu=new Student; $stu->show(); //這是子類注意事項:
1.13.2 方法重載
在同一個類中,有多個同名的函數,通過參數的不同來區分不同的方法,稱為方法重載
注意:PHP不支持方法重載,但是PHP可以通過其他方法來模擬方法重載。
1.14 私有屬性繼承和重寫
私有屬性可以繼承但不能重寫。
<?php class A {private $name='PHP';public function showA() {//var_dump($this); //object(B)#1 (2) { ["name":"B":private]=> string(4) "Java" ["name":"A":private]=> string(3) "PHP" } echo $this->name,'<br>'; //PHP} } class B extends A {private $name='Java';public function showB() {//var_dump($this); //object(B)#1 (2) { ["name":"B":private]=> string(4) "Java" ["name":"A":private]=> string(3) "PHP" } echo $this->name,'<br>'; //Java} } $obj=new B(); $obj->showA(); $obj->showB(); /*分析: showA()和showB()中的$this都表示B的對象,B中繼承了A的私有屬性,所以B中有兩個$name. 在showA()中只能訪問A中的$name,不能訪問B中的$name 在showB()中只能訪問B中的$name,不能訪問A中的$name */練習一
<?php class A {protected $name='tom'; public function showA() {echo $this->name,'<br>';} } class B extends A {public $name='berry';public function showB() {echo $this->name,'<br>';} } //測試 $obj=new B(); $obj->showA(); //berry $obj->showB(); //berry/* 分析:B中將A的$name重寫,所以$obj中只有一個$name,($name='berry'),不管$this在哪個方法中訪問,就只能訪問這個$name */練習二
<?php class A {private $name='tom'; public function showA() {echo $this->name,'<br>';} } class B extends A {public $name='berry';public function showB() {echo $this->name,'<br>';} } //測試 $obj=new B(); $obj->showA(); //tom $obj->showB(); //berry /* 分析: $obj中有兩個$name,一個是私有的,一個是公有的 在showA()中既能訪問私有的$name,也能訪問公有的$name,但是私有的比公有的權限高,所以輸出tom 在showB()中不能訪問私有的$name,只能訪問公有的$name,所以輸出berry */1.15 方法修飾符
方法修飾符有:static、final、abstract
1.15.1 static【靜態的】
練習:統計在線人數
<?php class Student {private static $num=0; //靜態變量,在內存中就一份public function __construct() {self::$num++; //self表示所在類的類名}public function __destruct() {self::$num--;}public function show() {echo '總人數是:'.self::$num,'<br>';} } //測試 $stu1=new Student; $stu2=new Student; $stu3=new Student; $stu2->show(); //總人數是:3 unset($stu2); $stu3->show(); //總人數是:2**注意:**self表示所在類的類名,使用self降低耦合性
靜態成員也可以被繼承
<?php class Person {public static $add='中國';public static function show() {echo '這是人類<br>';} } //繼承 class Student extends Person { } //測試 echo Student::$add,'<br>'; //中國 通過子類名稱訪問父類的靜態成員 Student::show(); //這是人類靜態延時綁定
static表示當前對象所屬的類
<?php class Person {public static $type='人類';public function show1() {//var_dump($this); //object(Student)#1 (0) { } //echo self::$type,'<br>'; //人類echo static::$type,'<br>'; //學生 延時綁定} } class Student extends Person {public static $type='學生';public function show2() {//var_dump($this); //object(Student)#1 (0) { } //echo self::$type,'<br>'; //學生echo static::$type,'<br>'; //學生} } //測試 $obj=new Student(); $obj->show1(); $obj->show2();小結:
1、static在內存中就一份,在類加載的時候分配空間
2、如果有多個修飾符,修飾符之間是沒有順序的
3、self表示所在類的類名
4、static表示當前對象所屬的類
5、static有兩個作用,第一表示靜態的,第二表示類名
1.15.2 final【最終的】
final修飾的方法不能被重寫
final修飾的類不能被繼承
作用
1、如果一個類確定不被繼承,一個方法確定不會被重寫,用final修飾可以提高執行效率。
2、如果一個方法不允許被其他類重寫,可以用final修飾。
1.15.3 abstract【抽象的】
例題
<?php //抽象類 abstract class Person {public abstract function setInfo(); //抽象方法public function getInfo() {echo '獲取信息<br>';} } //繼承 class Student extends Person {//重寫實現父類的抽象方法public function setInfo() {echo '重新實現父類的抽象方法<br>';} } //測試 $stu=new Student; $stu->setInfo(); //重新實現父類的抽象方法 $stu->getInfo(); //獲取信息抽象類的作用:
1定義命名規范
2、阻止實例化,如果一個類中所有的方法都是靜態方法,這時候沒有必要去實例化,可以通過abstract來阻止來的實例化。
1.16 類常量
類常量是const常量
<?php class Student {//public const ADD; //7.1以后才支持訪問修飾符const ADD='地址不詳'; } echo Student::ADD;問題:define常量和const常量的區別?
答:const常量可以做類成員,define常量不可以做類成員。
問題:常量和靜態的屬性的區別?
答:相同點:都在加載類的時候分配空間
? 不同點:常量的值不可以更改,靜態屬性的值可以更改
1.17 接口(interface)
1.17.1 接口
1.17.2 接口的多重實現
類不允許多重繼承,但是接口允許多重實現。
<?php interface IPic1 {function fun1(); } interface IPic2 {function fun2(); } //接口允許多重實現 class Student implements IPic1,IPic2 {public function fun1() {}public function fun2() {} }注意:
1、在接口的多重實現中,如果有同名的方法,只要實現一次即可
2、類可以繼承的同時實現接口
class Student extends Person implements IPIc1,IPic1{}1.18 匿名類
這是了解的內容,PHP7.0支持
<?php $stu=new class {public $name='tom';public function __construct() {echo '構造函數<br>';} }; echo $stu->name; /*運行結果; 構造函數 tom */小結:
1、如果類只被實例化一次就可以使用匿名類
2、好處,在執行的過程中,類不占用空間
1.19 方法綁定
這是了解的內容,PHP7.0支持
作用:將方法綁定到對象上,并調用
語法:
閉包->call(對象):將閉包綁定到對象上,并調用在PHP中匿名函數稱為閉包
例題
<?php $lang='en'; //類 class Student{ } //匿名函數 if($lang=='ch'){$fun=function(){echo '我是一名學生';}; }else{$fun=function(){echo 'i am a studnet';}; } //綁定 $stu=new Student; $fun->call($stu); //i am a studnet1.20 自動加載類
在項目開發中,因為一個文件中只能寫一個類,并且在執行過程中會有很多的類參與,如果一個一個的加載很麻煩,所以,就需要一個機制實現在PHP執行過程中自動加載需要的類。
1.20.1 類的規則
1.20.2 手動加載類
1、創建Goods.class.php頁面
<?php //商品類 abstract class Goods {protected $name;final public function setName($name) {$this->name=$name; }public abstract function getName(); }2、創建Book.class.php頁面
<?php //圖書類 class Book extends Goods {public function getName() {echo "《{$this->name}》<br>";} }3、創建Phone.class.php頁面
<?php //電話類 class Phone extends Goods {public function getName() {echo $this->name,'<br>';} }4、在PHP頁面上加載類文件
<?php require './Goods.class.php'; //手動加載類文件 require './Book.class.php'; //手動加載類文件 require './Phone.class.php'; //手動加載類文件 //測試 $book=new Book(); $book->setName('面向對象編程'); $phone=new Phone(); $phone->setName('蘋果6s'); $book->getName(); $phone->getName();運行結果
1.20.3 自動加載類
當缺少類的時候自動的調用__autoload()函數,并且將缺少的類名作為參數傳遞給__autoload()。
<?php /* *作用:自動加載類 *@param $class_name string 缺少的類名 */ function __autoload($class_name) {require "./{$class_name}.class.php"; } //測試 $book=new Book(); $book->setName('面向對象編程'); $phone=new Phone(); $phone->setName('蘋果6s'); $book->getName(); $phone->getName();注意:__autoload()函數在PHP7.2以后就不支持了。
1.20.4 注冊加載類
通過spl_autoload_register()注冊__autoload()函數
<?php //方法一: /* //加載類函數 function loadClass($class_name) {require "./{$class_name}.class.php"; } //注冊加載類函數 spl_autoload_register('loadClass'); *///方法二: spl_autoload_register(function($class_name){require "./{$class_name}.class.php"; });//測試 $book=new Book(); $book->setName('面向對象編程'); $phone=new Phone(); $phone->setName('蘋果6s'); $book->getName(); $phone->getName();1、spl_autoload_register()可以注冊多個自動加載函數
<?php function load1($class) {require "./{$class}.class.php"; } function load2($class) {require "./{$class}.php"; } function load3($class) {require "./{$class}.fun.php"; } spl_autoload_register('load1'); spl_autoload_register('load2'); spl_autoload_register('load3');2、PHP5.1以后就開始支持此函數。
1.20.5 類文件存儲不規則的加載方法
將類名和文件地址做一個映射,組成一個關聯數組。
$map=array(//類名 => 類文件地址'Goods' => './aa/Goods.class.php','Book' => './bb/Book.class.php','Phone' => './cc/Phone.class.php' );代碼如下
<?php spl_autoload_register(function($class_name){//類名和文件地址映射成一個關聯數組$map=array('Goods' => './aa/Goods.class.php','Book' => './bb/Book.class.php','Phone' => './cc/Phone.class.php');//在映射數組中找到就包含if(isset($map[$class_name]))require $map[$class_name]; }); //測試 $book=new Book(); $book->setName('面向對象編程'); $phone=new Phone(); $phone->setName('蘋果6s'); $book->getName(); $phone->getName();在項目中,絕大部分都是規則存儲的,不規則的比較少。
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的PHP-面向对象编程教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP-连接数据库
- 下一篇: 怎样在PHP中通过ADO调用Assces