bind是bindTo的靜態版本,因此只說bind吧。(還不是太瞭解為什麼要弄出兩個版本)
官方文件: 複製一個閉包,繫結指定的$this物件和類作用域。
其實後半句表述很不清楚。 我的理解: 把一個閉包轉換為某個類的方法(只是這個方法不需要通過物件呼叫), 這樣閉包中的$this、static、self就轉換成了對應的物件或類。
因為有幾種情況:
1、只繫結$this物件.\
2、只繫結類作用域.\
3、同時繫結$this物件和類作用域.(文件的說法)\
4、都不繫結.(這樣一來只是純粹的複製, 文件說法是使用cloning代替bind或bindTo)
下面詳細講解這幾種情況:
1、只繫結$this物件
$closure = function ($name, $age) {
$this->name = $name;
$this->age = $age;
};
class Person {
public $name;
public $age;
public function say() {
echo "My name is {$this->name}, I'm {$this->age} years old.\n";
}
}
$person = new Person();
//把$closure中的$this繫結為$person
//這樣在$bound_closure中設定name和age的時候實際上是設定$person的name和age
//也就是繫結了指定的$this物件($person)
$bound_closure = Closure::bind($closure, $person);
$bound_closure('php', 100);
$person->say();
注意: 在上面的這個例子中,是不可以在$closure中使用static的,如果需要使用static,通過第三個引數傳入帶名稱空間的類名。
2、只繫結類作用域.
$closure = function ($name, $age) {
static::$name = $name;
static::$age = $age;
};
class Person {
static $name;
static $age;
public static function say()
{
echo "My name is " . static::$name . ", I'm " . static::$age. " years old.\n";
}
}
//把$closure中的static繫結為Person類
//這樣在$bound_closure中設定name和age的時候實際上是設定Person的name和age
//也就是繫結了指定的static(Person)
$bound_closure = Closure::bind($closure, null, Person::class);
$bound_closure('php', 100);
Person::say();
注意: 在上面的例子中,是不可以在$closure中使用$this的,因為我們的bind只繫結了類名,也就是static,如果需要使用$this,新建一個物件作為bind的第二個引數傳入。
3、同時繫結$this物件和類作用域.(文件的說法)
$closure = function ($name, $age, $sex) {
$this->name = $name;
$this->age = $age;
static::$sex = $sex;
};
class Person {
public $name;
public $age;
static $sex;
public function say()
{
echo "My name is {$this->name}, I'm {$this->age} years old.\n";
echo "Sex: " . static::$sex . ".\n";
}
}
$person = new Person();
//把$closure中的static繫結為Person類, $this繫結為$person物件
$bound_closure = Closure::bind($closure, $person, Person::class);
$bound_closure('php', 100, 'female');
$person->say();
在這個例子中可以在$closure中同時使用$this和static
4、都不繫結.(這樣一來只是純粹的複製, 文件說法是使用cloning代替bind或bindTo)
$closure = function () {
echo "bind nothing.\n";
};
//與$bound_closure = clone $closure;的效果一樣
$bound_closure = Closure::bind($closure, null);
$bound_closure();
self 和static 的區別
class A {
protected $name = 'A';
static $alias = 'a';
const HASH = 'md5';
public function dd() {
echo $this->name; echo '--';
echo static::$alias; echo '--'; // 後期靜態繫結
echo static::HASH; echo '--'; // 後期靜態繫結
echo self::$alias; echo '--';
echo self::HASH; echo '--';
var_dump(new self); echo '--';
var_dump($this); echo '--';
var_dump(new static); echo '<br>'; // 後期靜態繫結
}
public static function who() {
echo __CLASS__;
echo ' [ This is A ]'; echo '<br>';
}
public static function test() {
self::who();
}
public static function test2() {
static::who(); // 後期靜態繫結
}
public static function getInstance() {
var_dump(new self); echo '--';
var_dump(new static); echo '<br>'; // 後期靜態繫結
}
}
class B extends A {
protected $name = 'B';
static $alias = 'b';
const HASH = 'sha1';
public static function who() {
echo __CLASS__;
echo ' [ This is B ]'; echo '<br>';
}
}
class C extends B {
public static function who() {
echo __CLASS__;
echo ' [ This is C]'; echo '<br>';
}
}
(new A)->dd(); // A--a--md5--a--md5--object(A)#2 (1) { ["name":protected]=> string(1) "A" } --object(A)#1 (1) { ["name":protected]=> string(1) "A" } --object(A)#2 (1) { ["name":protected]=> string(1) "A" }
(new B)->dd(); // B--b--sha1--a--md5--object(A)#2 (1) { ["name":protected]=> string(1) "A" } --object(B)#1 (1) { ["name":protected]=> string(1) "B" } --object(B)#2 (1) { ["name":protected]=> string(1) "B" }
A::who(); // A [ This is A ]
B::who(); // B [ This is B ]
A::test(); // A [ This is A ]
B::test(); // A [ This is A ]
A::test2(); // A [ This is A ]
B::test2(); // B [ This is B ]
C::test2(); // C [ This is C]
A::getInstance(); // object(A)#1 (1) { ["name":protected]=> string(1) "A" } --object(A)#1 (1) { ["name":protected]=> string(1) "A" }
B::getInstance(); // object(A)#1 (1) { ["name":protected]=> string(1) "A" } --object(B)#1 (1) { ["name":protected]=> string(1) "B" }
總結說明:
- self 和 CLASS,都是對當前類的靜態引用,取決於定義當前方法所在的類。也就是說,self 寫在哪個類裡面, 它引用的就是誰。
- $this 指向的是實際呼叫時的物件,也就是說,實際執行過程中,誰呼叫了類的屬性或方法,$this 指向的就是哪個物件。但 $this 不能訪問類的靜態屬性和常量,且 $this 不能存在於靜態方法中。
- static 關鍵字除了可以宣告類的靜態成員(屬性和方法)外,還有一個非常重要的作用就是後期靜態繫結。
- self 可以用於訪問類的靜態屬性、靜態方法和常量,但 self 指向的是當前定義所在的類,這是 self 的限制。
$this 指向的物件所屬的類和 static 指向的類相同。 - static 可以用於靜態或非靜態方法中,也可以訪問類的靜態屬性、靜態方法、常量和非靜態方法,但不能訪問非靜態屬性。
靜態呼叫時,static 指向的是實際呼叫時的類;非靜態呼叫時,static 指向的是實際呼叫時的物件所屬的類。
本作品採用《CC 協議》,轉載必須註明作者和本文連結