現在我們來了解一下面向對象的一個封裝性的問題
封裝性:在我的理解裡面 可以理解為一個u盤 我們使用u盤的接口與電腦進行數據之間的交互 但是我們不能看到裡面的結構 這個特性我們可以稱為封裝性
好處:利用這個特性我們可以最大程度的提高代碼的質量 我們在其他代碼中只要對接口進行引用不用每次都寫 提高代碼的自量 以及減少排除bug的難度
現在我們來思考個問題:個人電腦都有一個密碼,不想讓其它人隨意的登陸,在你電腦裡面拷貝和粘貼。還有就是像人這個對象, 身高和年齡的屬性, 只能是自己來增漲,不可以讓別人隨意的賦值等等。
我們使用private這個關鍵詞對代碼進行封裝
private $name; // 把人的姓名使用private關鍵字進行封裝
private $sex; // 把人的性別使用private關鍵字進行封裝
private $age; // 把人的年齡使用private關鍵字進行封裝
private function run(){……} // 把人的走路方法使用private關鍵字進行封裝
注意:只要成員屬性前面有其他的關鍵字,那麼就要去掉var
<?php
class Person
{
// 下面是人的成員屬性
private $name; // 人的名子,被private封裝上了
private $sex; // 人的性別, 被private封裝上了
private $age; // 人的年齡, 被private封裝上了
// 這個人可以說話的方法
function say()
{
echo "我的名子叫:" . $this->name . " 性別:" . $this->sex . " 我的年齡是:" . $this->age;
}
// 這個人可以走路的方法, 被private封裝上了
private function run()
{
echo "這個人在走路";
}
}
// 實例化一個人的實例對象
$p1 = new Person();
// 試圖去給私有的屬性賦值, 結果會發生錯誤
$p1->name = "張三";
$p1->sex = "男";
$p1->age = 20;
// 試圖去打印私有的屬性, 結果會發生錯誤
echo $p1->name;
echo $p1->sex;
echo $p1->age;
// 試圖去打印私有的成員方法, 結果會發生錯誤
$p1->run();
?>
輸出結果為:
Fatal error: Cannot access private property Person::$name
Fatal error: Cannot access private property Person::$sex
Fatal error: Cannot access private property Person::$age
Fatal error: Cannot access private property Person::$name
Fatal error: Call to private method Person::run() from context ' '
沒有加任何訪問控制,默認的是public的,任何地方都可以訪問。
// 這個人可以說話的方法, 說出自己的私有屬性,在這裡也可以訪問私有方法
function say()
{
echo "我的名子叫:" . $this->name . " 性別:" . $this->sex . " 我的年齡是:" . $this->age;
// 在這裡也可以訪問私有方法
//$this->run();
}
因為成員方法say()是公有的, 所以我們在類的外部調用say()方法是可以的,改變上面的代碼:
<?php
class Person
{
// 下面是人的成員屬性
private $name; //人的名子,被private封裝上了
private $sex; //人的性別, 被private封裝上了
private $age; //人的年齡, 被private封裝上了
// 定義一個構造方法參數為私有的屬性姓名$name、性別$sex和年齡$age進行賦值
function __construct($name, $sex, $age)
{
// 通過構造方法傳進來的$name給私有成員屬性$this->name賦初使值
$this->name = $name;
// 通過構造方法傳進來的$sex給私有成員屬性$this->sex賦初使值
$this->sex = $sex;
// 通過構造方法傳進來的$age給私有成員屬性$this->age賦初使值
$this->age = $age;
}
// 這個人可以說話的方法, 說出自己的私有屬性,在這裡也可以訪問私有方法
function say()
{
echo "我的名子叫:" . $this->name . " 性別:" . $this->sex . " 我的年齡是:" . $this->age;
}
}
// 通過構造方法創建3個對象$p1、p2、$p3,分別傳入三個不同的實參為姓名、性別和年齡
$p1 = new Person("張三", "男", 20);
$p2 = new Person("李四", "女", 30);
$p3 = new Person("王五", "男", 40);
// 下面訪問$p1對象中的說話方法
$p1->say();
// 下面訪問$p2對象中的說話方法
$p2->say();
// 下面訪問$p3對象中的說話方法
$p3->say();
?>
因為構造方法是默認的公有方法(構造方法不要設置成私有的),如果設置稱為私有的話,就等同將u盤中的唯一一個接口封死,我們就不能對這個類進行訪問
上面的例子中我們可以看到, 私有的成員只能在類的內部使用, 不能被類外部直接來存取 但是我們有時候有需要對私有屬性進行賦值和讀取,我們需要給類的外部提供一些可以存取的接口。
prvate $age; // 私有的屬性年齡
function setAge($age) // 為外部提供一個公有設置年齡的方法
{
if ($age<0 || $age>130) // 在給屬性賦值的時候,為了避免非法值設置給屬性
return;
$this->age = $age;
}
function getAge() // 為外部提供一個公有獲取年齡的方法
{
return($this->age);
}
下面我們要了解一下__set,__get,__isset,__unset四個方法的應用
經過上面的講解可能會有疑問 那麼我們如何對私有類進行操作呢?????
__set設置:__get
<?php
//__get()方法用來獲取私有屬性
function __get($property_name)
{
if (isset($this->$property_name))
{
return ($this->$property_name);
}
else
{
return (NULL);
}
}
//__set()方法用來設置私有屬性
function __set($property_name, $value)
{
$this->$property_name = $value;
}
一個完整的示例:
<?php
class Person
{
// 下面是人的成員屬性, 都是封裝的私有成員
private $name; //人的名子
private $sex; //人的性別
private $age; //人的年齡
//__get()方法用來獲取私有屬性
function __get($property_name)
{
echo "在直接獲取私有屬性值的時候,自動調用了這個__get()方法<br />";
if (isset($this->$property_name))
{
return ($this->$property_name);
}
else
{
return NULL;
}
}
//__set()方法用來設置私有屬性
function __set($property_name, $value)
{
echo "在直接設置私有屬性值的時候,自動調用了這個__set()方法為私有屬性賦值<br />";
$this->$property_name = $value;
}
}
$p1 = new Person();
// 直接為私有屬性賦值的操作, 會自動調用__set()方法進行賦值
$p1->name = "張三";
$p1->sex = "男";
$p1->age = 20;
// 直接獲取私有屬性的值, 會自動調用__get()方法,返回成員屬性的值
echo "姓名:" . $p1->name . "<br />";
echo "性別:" . $p1->sex . "<br />";
echo "年齡:" . $p1->age . "<br />";
?>
程序執行結果:
在直接設置私有屬性值的時候,自動調用了這個__set()方法為私有屬性賦值
在直接設置私有屬性值的時候,自動調用了這個__set()方法為私有屬性賦值
在直接設置私有屬性值的時候,自動調用了這個__set()方法為私有屬性賦值
在直接獲取私有屬性值的時候,自動調用了這個__get()方法
姓名:張三
在直接獲取私有屬性值的時候,自動調用了這個__get()方法
性別:男
在直接獲取私有屬性值的時候,自動調用了這個__get()方法
年齡:20
以上代碼如果不加上__get()和__set()方法,程序就會出錯,因為不能在類的外部操作私有成員,而上面的代碼是通過自動調用__get()和__set()方法來幫助我們直接存取封裝的私有成員的。
如果在一個對象外面使用“isset()”這個函數去測定對象裡面的成員是否被設定可不可以用它呢?分兩種情況,如果對象裡面成員是公有的,我們就可以使用這個函數來測定成員屬性,如果是私有的成員屬性,這個函數就不起作用了,原因就是因為私有的被封裝了,在外部不可見。那麼我們就不可以在對象的外部使用“isset()”函數來測定私有成員屬性是否被設定了呢?可以,你只要在類裡面加上一個“__isset()”方法就可以了,當在類外部使用”isset()”函數來測定對象裡面的私有成員是否被設定時,就會自動調用類裡面的“__isset()”方法了幫我們完成這樣的操作,“__isset()”方法也可以做成私有的。你可以在類裡面加上下面這樣的代碼就可以了:
private function __isset($nm)
{
echo "當在類外部使用isset()函數測定私有成員$nm時,自動調用<br />";
return isset($this->$nm);
}
完整例子
<?php
class Person
{
// 下面是人的成員屬性
private $name; //人的名子
private $sex; //人的性別
private $age; //人的年齡
// __get()方法用來獲取私有屬性
private function __get($property_name)
{
if (isset($this->$property_name))
{
return ($this->$property_name);
}
else
{
return NULL;
}
}
// __set()方法用來設置私有屬性
private function __set($property_name, $value)
{
$this->$property_name = $value;
}
// __isset()方法
private function __isset($nm)
{
echo "isset()函數測定私有成員時,自動調用<br />";
return isset($this->$nm);
}
//__unset()方法
private function __unset($nm)
{
echo "當在類外部使用unset()函數來刪除私有成員時自動調用的<br />";
unset($this->$nm);
}
}
$p1 = new Person();
$p1->name = "this is a person name";
// 在使用isset()函數測定私有成員時,自動調用__isset()方法幫我們完成,返回結果為true
echo var_dump(isset($p1->name)) . "<br >";
echo $p1->name . "<br />";
// 在使用unset()函數刪除私有成員時,自動調用__unset()方法幫我們完成,刪除name私有屬性
unset($p1->name);
// 已經被刪除了,所這行不會有輸出
echo $p1->name;
?>
輸出結果為:
isset()函數測定私有成員時,自動調用
boolean true
this is a person name
當在類外部使用unset()函數來刪除私有成員時自動調用的
isset()函數測定私有成員時,自動調用
下面我們要來了解的是繼承的知識



下面是人類的代碼
// 定義一個“人”類做為父類
class Person
{
// 下面是人的成員屬性
var $name; //人的名子
var $sex; //人的性別
var $age; //人的年齡
// 定義一個構造方法參數為屬性姓名$name、性別$sex和年齡$age進行賦值
function __construct($name, $sex, $age)
{
$this->name = $name;
$this->sex = $sex;
$this->age = $age;
}
// 這個人可以說話的方法, 說出自己的屬性
function say()
{
echo "我的名子叫:" . $this->name . " 性別:" . $this->sex . " 我的年齡是:" . $this->age;
}
}
下面是學生類的代碼
class Student
{
// 下面是人的成員屬性
var $name; // 人的名字
var $sex; // 人的性別
var $age; // 人的年齡
var $school; // 學生所在學校的屬性
// 定義一個構造方法參數為屬性姓名$name、性別$sex 和年齡$age 進行賦值
function __construct($name = "", $sex = "", $age = "", $school = "")
{
$this->name = $name;
$this->sex = $sex;
$this->age = $age;
$this->school = $school;
}
// 這個人可以說話的方法, 說出自己的屬性
function say()
{
echo "我的名字叫:" . $this->name . " 性別:" . $this->sex . " 我的年齡是:" . $this->age . "<br />";
}
// 這個學生學習的方法
function study()
{
echo "我的名字叫:" . $this->name . " 我正在" . $this->school . "學習<br />";
}
}
對學生類進行簡化
class Student extends Person
{
var $school; // 學生所在學校的屬性
// 這個學生學習的方法
function study()
{
echo "我的名字叫:" . $this->name . " 我正在" . $this->school . "學習<br />";
}
}
現在我們要考慮的是重載的問題
這個時候你可能會有疑問 php 好像是不能重載的,因為PHP是一門若語言的,傳統意義上的重載是有多個的方法名相同的方法,但是帶有不同個數的參,我們利用參數的不同調用不同的接口
我所說的重載是子類對父類的一個覆蓋
<?
// 定義一個"人"類做為父類
class Person
{
// 下面是人的成員屬性
var $name; // 人的名子
var $sex; // 人的性別
var $age; // 人的年齡
// 定義一個構造方法參數為屬性姓名$name、性別$sex和年齡$age進行賦值
function __construct($name, $sex, $age)
{
$this->name = $name;
$this->sex = $sex;
$this->age = $age;
}
// 這個人可以說話的方法, 說出自己的屬性
function say()
{
echo "我的名子叫:" . $this->name . " 性別:" . $this->sex . " 我的年齡是:" . $this->age;
}
}
class Student extends Person
{
var $school; // 學生所在學校的屬性
// 這個學生學習的方法
function study()
{
echo "我的名子叫:" . $this->name . " 我正在" . $this->school . " 學習";
}
// 這個學性可以說話的方法, 說出自己所有的屬性,覆蓋了父類的同名方法
function say()
{
echo "我的名子叫:" . $this->name . " 性別:" . $this->sex . " 我的年齡是:" . $this->age . " 我在" . $this->school . "上學";
}
}
?>
這樣就能實現了 這種方法歸根到底是的要點是:
1。子類要對父類繼承
2.子類的方法名要與父類的方法名相同
這個時候我們可能發現如果這個方法中有1000條代碼那麼 實現起來很不方便
此時我們,使用“parent::方法名”的方試來調用父類中被覆蓋的方法;
class Student extends Person
{
var $school; // 學生所在學校的屬性
// 這個學生學習的方法
function study()
{
echo "我的名子叫:" . $this->name . " 我正在" . $this->school . "學習";
}
// 這個學性可以說話的方法, 說出自己所有的屬性,覆蓋了父類的同名方法
function say()
{
// 使用父類的"類名::"來調用父類中被覆蓋的方法;
// Person::say();
// 或者使用"parent::"的方試來調用父類中被覆蓋的方法;
parent::say();
// 加上一點自己的功能
echo "我的年齡是:" . $this->age . " 我在" . $this->school . "上學";
}
}
對public,private,protected的區別
<?php
/**
* Define MyClass
*/
class MyClass
{
// Contructors must be public
public function __construct() { }
// Declare a public method
public function MyPublic() { }
// Declare a protected method
protected function MyProtected() { }
// Declare a private method
private function MyPrivate() { }
// This is public
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}
$myclass = new MyClass;
$myclass->MyPublic(); // Works
$myclass->MyProtected(); // Fatal Error
$myclass->MyPrivate(); // Fatal Error
$myclass->Foo(); // Public, Protected and Private work
/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// This is public
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate(); // Fatal Error
}
}
$myclass2 = new MyClass2;
$myclass2->MyPublic(); // Works
$myclass2->Foo2(); // Public and Protected work, not Private
?>
從上面的代碼我們可以總結如下
public:可以直接進行外部訪問
protected 間接的外部訪問 像U盤和電腦一樣 訪問需要一個接口 而那個接口就是需要一個子類 (子類繼承了父類的protected)
private 不能通過外部訪問
既然談到繼承的問題 如果我們想要一個類不被繼承那麼我們可以用final 去進行定義(只能定義類和方法,不能定義成員屬性)
1.final 標記的類不能被繼承
2.final標記的方法不能被子類覆蓋
<?php
final class Person
{
function say()
{
}
}
class Student extends Person
{
function say()
{
}
}
?>
會出現下面錯誤:
Fatal error: Class Student may not inherit from final class (Person)
<?php
class Person
{
final function say()
{
}
}
class Student extends Person
{
function say()
{
}
}
?>
理解static 和const的關鍵關鍵字的使用(self:)
static 字面上的意思就是靜態的意思 現在你可能會問靜態使用靜態有什麼好處?使用靜態的好處是:如果示例話成千上萬“人”的對象,裡面都有一個共有的屬性比如國籍“中國”,那麼我們可以建國籍這個屬性設置為靜態,在內存在開辟出一個位置,實例化的過程中成千上萬的人都會訪問內存中這個位置
static成員能夠限制外部的訪問,因為static的成員是屬於類的,是不屬於任何對象實例,是在類第一次被加載的時候分配的空間,其他類是無法訪問的,只對類的實例共享,能一定程度對類該成員形成保護;
這一點有點像網站中的全局變量
<?
class Person
{
// 下面是人的靜態成員屬性
public static $myCountry = "中國";
// var $name; //人的名子
// 這是人的靜態成員方法
public static function say()
{
echo "我是中國人";
}
}
// 輸出靜態屬性
echo Person::$myCountry;
// 訪問靜態方法
Person::say();
// 重新給靜態屬性賦值
Person::$myCountry = "美國";
echo Person::$myCountry;
?>
結果是:
中國我是中國人美國
也可以這麼寫
<?php
class MyClass
{
// 定義一個常量constant
const constant = 'constant value';
function showConstant()
{
echo self::constant . " "; // 使用self訪問,不要加“$”
}
}
echo MyClass::constant . " "; // 使用類名來訪問,也不加“$”
$class = new MyClass();
$class->showConstant();
// echo $class::constant; // 是不允許的
?>
用“const”修飾的成員屬性的訪問方式和“static”修飾的成員訪問的方式差不多,也是使用“類名”,在方法裡面使用“self”關鍵字。但是不用使用“$”符號,也不能使用對象來訪問。
<?php
class MyClass
{
// 定義一個常量constant
const constant = 'constant value';
function showConstant()
{
echo self::constant . " "; // 使用self訪問,不要加“$”
}
}
echo MyClass::constant . " "; // 使用類名來訪問,也不加“$”
$class = new MyClass();
$class->showConstant();
// echo $class::constant; // 是不允許的
?>