訪問控制
屬性和方法的訪問控制(可見標識):public
任何地方private
類自身protected
類自身,自子類及自父類
this
this
可以理解為這個類的一個例項
self
self
代表類本身
__construct
例項化時就會自動執行public function __construct() {}
__destruct
當物件對銷燬時自動執行public function __destruct(){}
類常量
定義合不可改變
const ONE = 1
const TWO = self::ONE + 1;
可以在類外部呼叫Class::Two
parent
parent
代表父類public function __construct(){ parent::__construct();}
final
final class Dad(){}
加到類定義前面表示Dad類不想被繼承
class Dad(){
final public function run(){} // 加到方法宣告前面,表示方法不想被子類重寫
}
namespace
namespace
必須放在程式碼檔案的第一行
受名稱空間影響的型別:類(包括抽像類,traits)、介面、函式和常量。
當沒有使用namespace
關鍵字指定名稱空間時,當前指令碼是存在於全域性名稱空間的。用\
表示。\Class1
類全在指定的名稱空間去查詢,沒找到則丟擲錯誤。
函式與常量,在指定名稱空間查詢,沒找到則到全域性名稱空間查詢
,還沒打到則拋錯。
函式
ns1\ns2\fn()
常量
define
定義的常量是全域性的,不受名稱空間影響。const
定義的常量受名稱空間影響。
namespace ns1\ns2;
const ONE = 1;
echo ns1\ns2\ONE;
use
匯入類
用use
匯入名稱空間下的類use ns1\ns2\class1;
用as
重新命名匯入的類use ns1\ns2\class1 as class2;
匯入函式
use function ns1\ns2\fn as fn1;
匯入常量
use const ns1\ns2\ONE;
自動載入
__autoload
function __autoload($className){ require $className . '.php';}
spl_autoload_register
傳匿名函式
spl_autoload_register(function($className){ require $className . '.php'; });
傳函式名
function test($className){ require $className . '.php'; }
spl_autoload_register('test');
傳類
class Momo
{
function autoload($className)
{
require $className . '.php';
}
}
spl_autoload_register([new Momo, 'autoload']);
static
宣告靜態屬性和靜態方法,不經過例項化,通過類名即可呼叫。
class Person()
{
public static $hand = '手';
public static function run()
{
echo 'running...';
}
}
echo Person::$hand;
Person::run();
類內部呼叫靜態屬性和靜態方法用self
關鍵字
echo self::$hand;
self::run();
呼叫父類的靜態屬性和靜態方法用parent
關鍵字
echo parent::$hand;
parent::run();
後期靜態繫結
class A
{
public static function who()
{
echo 'A類的who方法';
}
public static function test1()
{
self::who();
}
public static function test2()
{
static::who();
}
}
class B extends A
{
public static function who()
{
echo 'B類的who方法';
}
}
B::test1(); // test1內部用的self,呼叫的是自身(A類)的靜態方法
B::test2(); // 後期繫結。內部用static,根據後期的呼叫環境確定,呼叫的是B類的靜態方法
魔術方法
__set
class Test
{
private $name = '';
public function __set($var, $val)
{
// 對$val進行資料處理
$this->$var = $val;
}
}
$test = new Test();
$test->name = 'tom'; // 賦值tom
__get
class Test
{
private $name = 'jack';
public function __get($var)
{
return $this->$var;
}
}
$test = new Test();
echo $test->name; // jack
__isset
用於檢測私有屬性是否存在
class Test
{
private $name = 'mary';
public function __isset($var)
{
return isset($this->$var);
}
}
$test = new Test();
var_dump($test->name); // 如果不設定__isset,返回false,設定後返回true
__unset
用於刪除私有屬性
class Test
{
private $name = 'Levi';
public function __unset($var)
{
unset()
}
}
$test = new Test;
unset($test->name); // 會觸發__unset
__call
避免呼叫一個不存在的方法時產生錯誤,當呼叫的方法不存在時,__call
方法會自動呼叫
class Test
{
public function __call($fn_name, $fn_arguments)
{
echo $fn_name;
print_r($fn_arguments);
}
}
$test = new Test();
$test->go(1, 'ok'); // 自動呼叫`__call`方法,列印出函式名和引數陣列
__callStatic
同__call
類似
避免呼叫一個不存在的靜態方法
class Test
{
public static function __callStatic($fn_name, $fn_arguments)
{
echo $fn_name;
print_r($fn_arguments);
}
}
// `__callStatic` 必須宣告為靜態方法
Test::go(1, 'ok');
__invoke
當物件以函式的形式呼叫的時候,自動呼叫__invoke
方法
class Test
{
public function __invoke($args)
{
return $args;
}
}
$test = new Test();
$test('go.....'); // 執行__invoke
__toString
當列印物件是會呼叫__toString
方法
class Test
{
public function __toString()
{
return 'Hello world!';
}
}
$test = new Test;
echo $test; // 輸出 Hello world!
物件複製
淺拷貝
比較省記憶體,物件的拷貝預設是淺拷貝。
$a = new Test();
$b = $a; // 淺拷貝。傳址。改變$b。$a也會改變。
物件的複製是淺拷貝的。傳址。
普通變數的拷貝是深拷貝的。傳值。
深拷貝
$a = new Test();
$b = clone $a; // 深拷貝。改變$b,不會改變$a。
__clone
當使用clone
關鍵字時,自動呼叫__clone
方法
class Test
{
public $obj = null;
public function __clone()
{
$this->obj = clone $this->obj;
}
}
class Person
{
public $sex = 0;
}
$a = new Test;
$a->obj = new Person;
$b = clone $a; // 觸發`__clone` 對obj進行深拷貝
$b->obj->sex = 1; // $b中的obj物件改變了。而$a中的obj物件沒變。
型別約束
class A
{
public function go()
{
echo 'go .....';
}
}
function test(A $a) {
$a->go();
}
test(new A());
Trait
單繼承語言PHP的程式碼複用機制。
Trait Bt
{
public function atest()
{
echo 'Hello ';
}
public function btest()
{
echo 'world';
}
public function ab()
{
$this->atest();
$this->btest();
}
}
class Test
{
use Bt; // 使用Bt Trait,便擁有了Bt所有的方法
}
$test = new Test;
$test->ab();
繼承多個Trait
Trait A
{
public $name = 'tom';
public function a()
{
echo 'Hello ';
}
}
Trait B
{
public function b()
{
echo 'world ';
}
}
class Test
{
use A,B;
public function c()
{
echo $this->name;
}
}
$test = new Test;
$test->a();
$test->b();
$test->c(); // Hello world tom
Trait 支援巢狀
Trait A{}
Trait B{}
Trait C
{
use A,B;
}
Class Test
{
use C;
}
interface
介面是類的模板。在介面中只定義需要實現的空方法,這些方法在介面中不做具體實現。
介面是不能被例項化的。
Interface Person
{
public function eat();
public function sleep();
}
class man implements Person
{
public function eat()
{
echo 'eating...';
}
public function sleep()
{
echo 'sleeping...';
}
}
class L
{
public static function factory(Person $user) // 用介面作型別約束
{
return $user;
}
}
$user = L::factory(new Man());
$user->eat();
$user->sleep();
介面可以繼承介面。
介面可以繼承多個介面。
介面可以使用常量,叫介面常量,和類的常量使用方法相同
Interface Ia
{
const ONE = 1;
public function eat();
}
Interface Ib
{
public function sleep();
}
Interface AB extends Ia,Ib
{}
// class Test implements Ia,Ib 類可以同時繼承多個介面
class Test implements AB
{
public function eat()
{
echo 'eating...';
}
public function sleep()
{
echo 'sleeping...';
}
}
$test = new Test;
$test->eat();
$test->sleep();
echo Ia::ONE; // 使用介面常量
abstract
抽象類不能被例項化。
如果至少有一個方法被宣告為抽象的,那麼這個類必須被宣告為抽象的。
抽象方法只能宣告,不能有具體功能實現。
抽象類可以有被實現的的方法。
繼承抽象類,子類必須實現父類中所有的抽象方法。
這些方法的訪問控制必須和父類一樣,或者更寬鬆,不能比父類更嚴格。
方法的呼叫方式也必須匹配。型別和引數數量必須一致,但子類可以定義父類中不存在的可選引數。
abstract AB
{
public function run()
{
echo 'running...';
}
abstract public function eat();
abstract public function sleep();
}
class Test extends AB
{
public function eat()
{
echo 'eating...';
}
public function sleep($time = '21:00 PM') // 可以定義父類方法中不存在的可選引數
{
echo 'sleep @ ' . $time;
}
}
單例模式
只能被例項化一次,節省記憶體空間
class Test
{
private static $instance = null;
private function __constrct()
{}
private function __clone()
{}
public static function getInstance()
{
if (!(self::instance instanceof self)) {
self::instance = new self();
}
return self::instance;
}
}
$test = Test::getInstance(); // 多次呼叫也只是例項化一次
工廠模式
Interface CacheI
{
public function set($key, $value);
public function get($key);
public function delete($key);
}
class Memcache implements CacheI
{
public function set($key, $value){}
public function get($key){}
public function delete($ke){}
}
class Redis implements CacheI
{
public function set($key, $value){}
public function get($key){}
public function delete($ke){}
}
class Cache
{
public static function factory()
{
return new Memcache(); // 這裡可以是繼承了CacheI介面的任何類,比如Redis
}
}
$cache = Cache::factory();
$cache->set('name', 'tom');
$cache->get('name');
$cache->delete('name');