ใน PHP 5 อะไรคือความแตกต่างระหว่างการใช้self
และ$this
?
แต่ละคนมีความเหมาะสมเมื่อใด
ใน PHP 5 อะไรคือความแตกต่างระหว่างการใช้self
และ$this
?
แต่ละคนมีความเหมาะสมเมื่อใด
คำตอบ:
ใช้
$this
เพื่ออ้างถึงวัตถุปัจจุบัน ใช้self
เพื่ออ้างถึงคลาสปัจจุบัน กล่าวอีกนัยหนึ่งใช้$this->member
สำหรับสมาชิกที่ไม่คงที่ใช้self::$member
สำหรับสมาชิกคงที่
นี่คือตัวอย่างของการใช้งานที่ถูกต้องของ$this
และself
สำหรับตัวแปรสมาชิกแบบไม่คงที่และแบบคงที่:
<?php
class X {
private $non_static_member = 1;
private static $static_member = 2;
function __construct() {
echo $this->non_static_member . ' '
. self::$static_member;
}
}
new X();
?>
นี่คือตัวอย่างของการใช้งานที่ไม่ถูกต้องของ$this
และself
สำหรับสมาชิกที่ไม่คงที่และคงที่:
<?php
class X {
private $non_static_member = 1;
private static $static_member = 2;
function __construct() {
echo self::$non_static_member . ' '
. $this->static_member;
}
}
new X();
?>
นี่คือตัวอย่างของความแตกต่างที่มี$this
ฟังก์ชั่นสมาชิก
<?php
class X {
function foo() {
echo 'X::foo()';
}
function bar() {
$this->foo();
}
}
class Y extends X {
function foo() {
echo 'Y::foo()';
}
}
$x = new Y();
$x->bar();
?>
นี่คือตัวอย่างของการยับยั้งพฤติกรรม polymorphicโดยใช้self
สำหรับฟังก์ชันสมาชิก:
<?php
class X {
function foo() {
echo 'X::foo()';
}
function bar() {
self::foo();
}
}
class Y extends X {
function foo() {
echo 'Y::foo()';
}
}
$x = new Y();
$x->bar();
?>
แนวคิดคือ
$this->foo()
เรียกfoo()
ฟังก์ชันสมาชิกของสิ่งที่เป็นชนิดที่แน่นอนของวัตถุปัจจุบัน ถ้าวัตถุเป็นของมันจึงเรียกtype X
X::foo()
ถ้าวัตถุเป็นของมันเรียกtype Y
Y::foo()
แต่ด้วยตัวเอง :: foo ()X::foo()
มักถูกเรียก
จากhttp://www.phpbuilder.com/board/showthread.php?t=10354489 :
self
จะใช้กับตัวดำเนินการแก้ไขขอบเขต::
เพื่ออ้างอิงคลาสปัจจุบัน สิ่งนี้สามารถทำได้ทั้งในบริบทคงที่และไม่คงที่ นอกจากนี้การใช้$this
วิธีการแบบคงที่นั้นถูกต้องตามกฎหมายอย่างสมบูรณ์
$this::
อะไร
คำหลักนั้นไม่ได้อ้างถึงเพียงแค่ 'คลาสปัจจุบัน' อย่างน้อยก็ไม่ใช่ในแบบที่ จำกัด ให้คุณเป็นสมาชิกแบบสแตติก ภายในบริบทของสมาชิกที่ไม่คงที่self
ยังมีวิธีการข้าม vtable ( ดูวิกิบน vtable ) สำหรับวัตถุปัจจุบัน เช่นเดียวกับที่คุณสามารถใช้parent::methodName()
เพื่อเรียกใช้ฟังก์ชัน parent เวอร์ชันดังนั้นคุณสามารถเรียกใช้self::methodName()
การเรียกคลาสปัจจุบันของเมธอดได้
class Person {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function getTitle() {
return $this->getName()." the person";
}
public function sayHello() {
echo "Hello, I'm ".$this->getTitle()."<br/>";
}
public function sayGoodbye() {
echo "Goodbye from ".self::getTitle()."<br/>";
}
}
class Geek extends Person {
public function __construct($name) {
parent::__construct($name);
}
public function getTitle() {
return $this->getName()." the geek";
}
}
$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();
สิ่งนี้จะออก:
สวัสดีค่ะฉันลุดวิกเป็นคนที่รัก
ลาก่อนจากลุดวิกเป็นคน
sayHello()
ใช้$this
ตัวชี้เพื่อ vtable Geek::getTitle()
จะเรียกเพื่อโทร
sayGoodbye()
ใช้self::getTitle()
ดังนั้น vtable ไม่ได้ใช้และPerson::getTitle()
ถูกเรียกใช้ ในทั้งสองกรณีเรากำลังจัดการกับวิธีการของวัตถุ instantiated และมีการเข้าถึง$this
ตัวชี้ภายในฟังก์ชั่นที่เรียกว่า
self
ตั้งอยู่" / "คำจำกัดความของคลาสมันเป็นส่วนที่แท้จริงของ" เช่นเดียวกับ "คลาสของวัตถุ" (ซึ่งจริง ๆ แล้วจะเป็นstatic
)
$this::
อะไร
$this::
; ทุกกรณีที่เป็นไปได้ถูกครอบคลุมโดยไวยากรณ์ที่ใช้กันทั่วไปมากกว่า ทั้งนี้ขึ้นอยู่กับสิ่งที่คุณหมายถึงการใช้งาน$this->
, หรือself::
static::
ห้ามใช้self::
ใช้งานstatic::
มีแง่มุมอื่นของตัวเอง :: ที่น่ากล่าวถึง annoyingly หมายถึงขอบเขตที่จุดของความหมายที่ไม่ได้อยู่ที่จุดของการดำเนินการself::
ลองพิจารณาคลาสง่ายๆนี้ด้วยสองวิธี:
class Person
{
public static function status()
{
self::getStatus();
}
protected static function getStatus()
{
echo "Person is alive";
}
}
หากเราโทรหาPerson::status()
เราจะเห็น "บุคคลมีชีวิตอยู่" พิจารณาสิ่งที่เกิดขึ้นเมื่อเราสร้างคลาสที่สืบทอดจากสิ่งนี้:
class Deceased extends Person
{
protected static function getStatus()
{
echo "Person is deceased";
}
}
โทรDeceased::status()
เราคาดว่าจะเห็น "บุคคลจะตาย" แต่สิ่งที่เราเห็นคือ "คนที่ยังมีชีวิตอยู่" เป็นขอบเขตมีความหมายวิธีการเดิมเมื่อการเรียกร้องให้self::getStatus()
ถูกกำหนด
PHP 5.3 มีทางออก static::
ความละเอียดการดำเนินการผู้ประกอบการ "คงที่ปลายผูกพัน" ซึ่งเป็นวิธีที่จินตนาการของบอกว่าก็ผูกพันกับขอบเขตของระดับที่เรียกว่า เปลี่ยนบรรทัดstatus()
เป็น static::getStatus()
และผลลัพธ์คือสิ่งที่คุณคาดหวัง ใน PHP เวอร์ชั่นเก่าคุณจะต้องหา kludge เพื่อทำสิ่งนี้
ดังนั้นเพื่อตอบคำถามที่ไม่ได้ถาม ...
$this->
อ้างถึงวัตถุปัจจุบัน (อินสแตนซ์ของคลาส) ในขณะที่static::
อ้างอิงถึงคลาส
getStatus
วิธีเป็นวิธีที่ฉันจะเรียกใช้อินสแตนซ์ของชั้นเรียนไม่ใช่สำหรับชั้นเรียน
self::
คุณจะได้รับน้อย อย่างสับสนโดยใช้ชื่อคลาสเฉพาะเช่นMyClass::
.
เพื่อให้เข้าใจสิ่งที่เรากำลังพูดถึงเมื่อเราพูดถึงself
เมื่อเทียบกับที่$this
เราต้องขุดจริงในสิ่งที่เกิดขึ้นในระดับแนวคิดและการปฏิบัติ ฉันไม่รู้สึกว่าคำตอบใด ๆ ทำอย่างเหมาะสมดังนั้นนี่คือความพยายามของฉัน
มาเริ่มกันด้วยการพูดคุยกันว่าคลาสและวัตถุคืออะไร
ดังนั้นสิ่งที่เป็นระดับ ? ผู้คนจำนวนมากกำหนดว่าเป็นพิมพ์เขียวหรือแม่แบบสำหรับวัตถุ ในความเป็นจริงคุณสามารถอ่านข้อมูลเพิ่มเติมเกี่ยวกับการเรียนใน PHP ที่นี่ และในระดับหนึ่งนั่นคือสิ่งที่มันเป็นจริง ลองดูชั้นเรียน:
class Person {
public $name = 'my name';
public function sayHello() {
echo "Hello";
}
}
ขณะที่คุณสามารถบอกได้มีสถานที่ให้บริการในระดับที่เรียกว่า$name
และวิธีการ (ฟังก์ชั่น) sayHello()
ที่เรียกว่า
มันสำคัญมากที่จะต้องทราบว่าคลาสนี้เป็นโครงสร้างแบบสแตติก ซึ่งหมายความว่าคลาสที่Person
กำหนดครั้งเดียวจะเหมือนกันทุกที่ที่คุณดู
วัตถุในอีกทางหนึ่งคือสิ่งที่เรียกว่าอินสแตนซ์ของคลาส สิ่งที่หมายถึงคือเราใช้ "พิมพ์เขียว" ของชั้นเรียนและใช้มันเพื่อทำสำเนาแบบไดนามิก ขณะนี้สำเนานี้เชื่อมโยงกับตัวแปรที่เก็บไว้เป็นพิเศษดังนั้นการเปลี่ยนแปลงใด ๆ กับอินสแตนซ์จะเป็นแบบโลคัลกับอินสแตนซ์นั้น
$bob = new Person;
$adam = new Person;
$bob->name = 'Bob';
echo $adam->name; // "my name"
เราสร้างอินสแตนซ์ใหม่ของคลาสโดยใช้new
โอเปอเรเตอร์
ดังนั้นเราจึงบอกว่าคลาสเป็นโครงสร้างระดับโลกและวัตถุเป็นโครงสร้างในท้องถิ่น ไม่ต้องกังวลเกี่ยวกับ->
ไวยากรณ์ที่ตลกเราจะเข้าไปในนั้นเล็กน้อย
สิ่งอื่น ๆ หนึ่งที่เราควรจะพูดคุยเกี่ยวกับการเป็นว่าเราสามารถตรวจสอบถ้าตัวอย่างเป็นinstanceof
ชั้นโดยเฉพาะอย่างยิ่ง$bob instanceof Person
ซึ่งผลตอบแทนแบบบูลถ้า$bob
อินสแตนซ์ที่ถูกสร้างขึ้นโดยใช้Person
ชั้นเรียนหรือPerson
เด็กของ
ลองขุดลงไปในสิ่งที่คลาสมีอยู่จริง มี "สิ่ง" 5 ประเภทที่ชั้นเรียนมี:
คุณสมบัติ - คิดว่าสิ่งเหล่านี้เป็นตัวแปรที่แต่ละอินสแตนซ์จะมี
class Foo {
public $bar = 1;
}
คุณสมบัติคงที่ - คิดว่าสิ่งเหล่านี้เป็นตัวแปรที่ใช้ร่วมกันในระดับชั้นเรียน หมายความว่าไม่มีการคัดลอกโดยแต่ละอินสแตนซ์
class Foo {
public static $bar = 1;
}
วิธีการ - เป็นฟังก์ชั่นที่แต่ละอินสแตนซ์จะมี (และทำงานกับอินสแตนซ์)
class Foo {
public function bar() {}
}
วิธีการคงที่ - เหล่านี้เป็นฟังก์ชั่นที่ใช้ร่วมกันทั่วทั้งชั้นเรียน พวกเขาไม่ทำงานบนอินสแตนซ์ แต่แทนในคุณสมบัติคงที่เท่านั้น
class Foo {
public static function bar() {}
}
ค่าคงที่ - ค่าคงที่คลาสที่แก้ไข ไม่ได้ไปที่นี่ลึก แต่เพิ่มเพื่อความสมบูรณ์:
class Foo {
const BAR = 1;
}
โดยพื้นฐานแล้วเรากำลังจัดเก็บข้อมูลในคลาสและวัตถุคอนเทนเนอร์โดยใช้ "คำแนะนำ" เกี่ยวกับสแตติกซึ่งระบุว่าข้อมูลนั้นถูกแชร์ (และด้วยเหตุนี้คงที่) หรือไม่
ภายในเมธอดอินสแตนซ์ของวัตถุจะถูกแทนด้วย$this
ตัวแปร สถานะปัจจุบันของวัตถุนั้นอยู่ที่นั่นและการกลายพันธุ์ (การเปลี่ยนแปลง) คุณสมบัติใด ๆ จะส่งผลให้เกิดการเปลี่ยนแปลงกับอินสแตนซ์นั้น (แต่ไม่ใช่อื่น ๆ )
หากวิธีการที่เรียกว่าแบบคงที่$this
ตัวแปรไม่ได้กำหนดไว้ นี่เป็นเพราะไม่มีอินสแตนซ์ที่เกี่ยวข้องกับการโทรคงที่
สิ่งที่น่าสนใจที่นี่คือวิธีการโทรออก ดังนั้นเรามาพูดถึงวิธีที่เราเข้าถึงรัฐ:
ดังนั้นตอนนี้ที่เราได้จัดเก็บสถานะนั้นเราต้องเข้าถึงมัน นี้จะได้รับบิตหากิน (หรือวิธีอื่น ๆ อีกมากมายกว่าบิต) จึงขอแยกนี้เป็นสองมุมมอง: จากด้านนอกของอินสแตนซ์ / คลาส (พูดจากสายการทำงานตามปกติหรือจากขอบเขตทั่วโลก) และภายในของอินสแตนซ์ / class (จากภายในเมธอดบนวัตถุ)
จากตัวอย่าง / คลาสภายนอกกฎของเราค่อนข้างง่ายและคาดเดาได้ เรามีโอเปอเรเตอร์สองตัวและแต่ละตัวจะบอกเราทันทีถ้าเราจัดการกับอินสแตนซ์หรือคลาสคงที่:
->
- ผู้ประกอบการวัตถุ - นี้จะใช้เสมอเมื่อเราเข้าถึงอินสแตนซ์
$bob = new Person;
echo $bob->name;
สิ่งสำคัญคือต้องทราบว่าการโทรPerson->foo
ไม่สมเหตุสมผล (เนื่องจากPerson
เป็นคลาสไม่ใช่ตัวอย่าง) ดังนั้นจึงเป็นข้อผิดพลาดในการแยกวิเคราะห์
::
- scope-resolution-operator - ใช้สำหรับเข้าถึงคุณสมบัติหรือเมธอด Class แบบคงที่เสมอ
echo Foo::bar()
นอกจากนี้เราสามารถเรียกใช้วิธีการคงที่บนวัตถุในลักษณะเดียวกัน:
echo $foo::bar()
เป็นสิ่งสำคัญอย่างยิ่งที่จะต้องทราบว่าเมื่อเราทำสิ่งนี้จากภายนอกอินสแตนซ์ของวัตถุนั้นถูกซ่อนไว้จากbar()
วิธีการ หมายความว่าเหมือนกับการทำงาน:
$class = get_class($foo);
$class::bar();
ดังนั้นจึง$this
ไม่ได้กำหนดไว้ในสายคงที่
สิ่งต่าง ๆ เปลี่ยนไปเล็กน้อยที่นี่ มีการใช้ตัวดำเนินการเดียวกัน แต่ความหมายจะเบลออย่างมีนัยสำคัญ
ประกอบวัตถุ ->
ยังคงใช้ในการโทรให้กับวัตถุของรัฐเช่น
class Foo {
public $a = 1;
public function bar() {
return $this->a;
}
}
เรียกbar()
วิธีการใน$foo
(อินสแตนซ์ของFoo
) โดยใช้วัตถุที่ผู้ประกอบการ: จะส่งผลในรุ่นอินสแตนซ์ของ$foo->bar()
$a
นั่นคือสิ่งที่เราคาดหวัง
ความหมายของ::
ผู้ประกอบการแม้ว่าการเปลี่ยนแปลง ขึ้นอยู่กับบริบทของการเรียกฟังก์ชั่นปัจจุบัน:
ภายในบริบทแบบคงที่
ภายในบริบทแบบคงที่การโทรใด ๆ ที่ใช้::
จะเป็นแบบสแตติก ลองดูตัวอย่าง:
class Foo {
public function bar() {
return Foo::baz();
}
public function baz() {
return isset($this);
}
}
การโทรFoo::bar()
จะเรียกbaz()
วิธีการแบบคงที่และด้วยเหตุนี้$this
จะไม่ถูกบรรจุ เป็นที่น่าสังเกตว่าในเวอร์ชันล่าสุดของ PHP (5.3+) สิ่งนี้จะทริกเกอร์E_STRICT
ข้อผิดพลาดเนื่องจากเรากำลังเรียกวิธีการที่ไม่คงที่
ภายในบริบทของอินสแตนซ์
ภายในบริบทอินสแตนซ์ในทางกลับกันการโทรที่ใช้โดย::
ขึ้นอยู่กับผู้รับการโทร (วิธีการที่เราโทร) หากมีการกำหนดวิธีการเป็นstatic
แล้วมันจะใช้การโทรคงที่ หากไม่เป็นเช่นนั้นก็จะส่งต่อข้อมูลอินสแตนซ์
ดังนั้นการดูรหัสข้างต้นการโทร$foo->bar()
จะกลับมาtrue
เนื่องจากการโทร "คงที่" เกิดขึ้นภายในบริบทอินสแตนซ์
ทำให้รู้สึก? ไม่คิดอย่างนั้น มันสับสน
เนื่องจากการผูกทุกอย่างร่วมกันโดยใช้ชื่อคลาสค่อนข้างสกปรก PHP จึงให้คำหลัก "ทางลัด" พื้นฐาน 3 รายการเพื่อให้การแก้ไขขอบเขตทำได้ง่ายขึ้น
self
- สิ่งนี้อ้างถึงชื่อคลาสปัจจุบัน ดังนั้นself::baz()
เป็นเช่นเดียวกับFoo::baz()
ในFoo
ชั้นเรียน (วิธีการใด ๆ กับมัน)
parent
- สิ่งนี้อ้างถึง parent ของคลาสปัจจุบัน
static
- นี่หมายถึงคลาสที่เรียกว่า ต้องขอบคุณการสืบทอดคลาสลูกสามารถแทนที่เมธอดและคุณสมบัติแบบสแตติก ดังนั้นการเรียกพวกเขาโดยใช้static
แทนชื่อคลาสช่วยให้เราสามารถแก้ไขได้ว่าการโทรนั้นมาจากที่ใดมากกว่าระดับปัจจุบัน
วิธีที่ง่ายที่สุดที่จะเข้าใจสิ่งนี้คือเริ่มดูตัวอย่าง เลือกชั้นเรียนกันเถอะ:
class Person {
public static $number = 0;
public $id = 0;
public function __construct() {
self::$number++;
$this->id = self::$number;
}
public $name = "";
public function getName() {
return $this->name;
}
public function getId() {
return $this->id;
}
}
class Child extends Person {
public $age = 0;
public function __construct($age) {
$this->age = $age;
parent::__construct();
}
public function getName() {
return 'child: ' . parent::getName();
}
}
ทีนี้เราก็ดูมรดกที่นี่ด้วย ไม่สนใจสักครู่ว่านี่เป็นโมเดลวัตถุที่ไม่ดี แต่ให้ดูว่าเกิดอะไรขึ้นเมื่อเราเล่นกับสิ่งนี้:
$bob = new Person;
$bob->name = "Bob";
$adam = new Person;
$adam->name = "Adam";
$billy = new Child;
$billy->name = "Billy";
var_dump($bob->getId()); // 1
var_dump($adam->getId()); // 2
var_dump($billy->getId()); // 3
ดังนั้นตัวนับ ID จะถูกแชร์ในทั้งอินสแตนซ์และลูก (เพราะเราใช้self
เพื่อเข้าถึงถ้าเราใช้static
เราสามารถแทนที่มันในคลาสย่อย)
var_dump($bob->getName()); // Bob
var_dump($adam->getName()); // Adam
var_dump($billy->getName()); // child: Billy
โปรดทราบว่าเรากำลังดำเนินการวิธีการPerson::getName()
อินสแตนซ์ทุกครั้ง แต่เรากำลังใช้สิ่งที่parent::getName()
ต้องทำในกรณีใดกรณีหนึ่ง (กรณีรอง) นี่คือสิ่งที่ทำให้วิธีการนี้มีประสิทธิภาพ
โปรดทราบว่าบริบทการโทรคือสิ่งที่พิจารณาว่ามีการใช้อินสแตนซ์ ดังนั้น:
class Foo {
public function isFoo() {
return $this instanceof Foo;
}
}
ไม่เป็นความจริงเสมอไป
class Bar {
public function doSomething() {
return Foo::isFoo();
}
}
$b = new Bar;
var_dump($b->doSomething()); // bool(false)
ตอนนี้มันแปลกจริงๆ ที่นี่ เรากำลังเรียกระดับที่แตกต่างกัน แต่$this
ที่ได้รับการส่งผ่านไปยังวิธีการเป็นตัวอย่างของFoo::isFoo()
$bar
สิ่งนี้สามารถทำให้เกิดบั๊กได้ทุกประเภทและแนวคิด WTF-ery ดังนั้นผมจึงขอแนะนำให้หลีกเลี่ยงต้องการ::
ผู้ประกอบการจากภายในเช่นวิธีการในสิ่งที่ยกเว้นผู้ที่เสมือน "ตัดสั้น" คำหลักที่สาม ( static
, self
และparent
)
โปรดทราบว่าทุกคนจะใช้วิธีและคุณสมบัติแบบคงที่ นั่นทำให้พวกเขาเป็นตัวแปรระดับโลก ด้วยปัญหาเดียวกันทั้งหมดที่มากับกลม ดังนั้นฉันจะลังเลที่จะเก็บข้อมูลในวิธีการ / คุณสมบัติคงที่จนกว่าคุณจะพอใจกับการเป็นข้อมูลระดับโลกอย่างแท้จริง
โดยทั่วไปคุณจะต้องการที่จะใช้สิ่งที่เรียกว่าปลายคงผูกพันโดยใช้แทนstatic
self
แต่โปรดทราบว่าพวกเขาไม่เหมือนกันดังนั้นการพูดว่า "ใช้static
แทนการself
เป็นสายตาสั้นจริง ๆ แทนหยุดและคิดเกี่ยวกับการโทรที่คุณต้องการสร้างและคิดว่าถ้าคุณต้องการให้คลาสเด็กสามารถแทนที่การแก้ไขแบบคงที่ได้โทร.
แย่มากลองย้อนกลับไปอ่าน อาจยาวเกินไป แต่ก็นานเพราะเป็นหัวข้อที่ซับซ้อน
ตกลงไม่เป็นไร. ในระยะสั้นself
จะใช้ในการอ้างอิงชื่อระดับปัจจุบันที่อยู่ในชั้นเรียนที่เป็น$this
หมายถึงวัตถุปัจจุบันเช่น โปรดทราบว่าself
เป็นการคัดลอก / วางทางลัด คุณสามารถแทนที่ด้วยชื่อคลาสของคุณได้อย่างปลอดภัยและมันจะทำงานได้ดี แต่$this
เป็นตัวแปรแบบไดนามิกที่ไม่สามารถระบุได้ล่วงหน้า (และอาจไม่ได้เป็นคลาสของคุณ)
หากใช้ตัวดำเนินการวัตถุ ( ->
) คุณจะรู้อยู่เสมอว่าคุณกำลังเผชิญกับอินสแตนซ์ หากใช้ตัวดำเนินการแก้ปัญหาขอบเขต ( ::
) คุณต้องการข้อมูลเพิ่มเติมเกี่ยวกับบริบท (เราอยู่ในบริบทของวัตถุอยู่แล้วหรือไม่เราอยู่นอกวัตถุหรือไม่ ฯลฯ )
$this
จะไม่ถูกกำหนดถ้าคุณทำตาม "มาตรฐานที่เข้มงวด" และไม่เรียกวิธีการแบบคงที่ที่ไม่ได้กำหนดเป็นแบบคงที่ ฉันเห็นผลลัพธ์ที่คุณอธิบายที่นี่: 3v4l.org/WeHVMเห็นด้วยแปลกจริง ๆ
Foo::isFoo()
เรียกว่าแบบสแตติก$this
จะไม่ถูกกำหนด นั่นเป็นพฤติกรรมที่ใช้งานง่ายในความคิดของฉัน - อีกผลที่แตกต่างกันจะได้รับหากมีการขยายจากBar
Foo
จากนั้นการโทรFoo::isFoo()
จะเป็นจริงในบริบทอินสแตนซ์ (ไม่เฉพาะ PHP7)
self
(ไม่ใช่ $ self) หมายถึงประเภทของคลาสโดยที่$this
อ้างอิงถึงอินสแตนซ์ปัจจุบันของคลาส self
สำหรับใช้ในฟังก์ชั่นสมาชิกแบบคงที่เพื่อให้คุณสามารถเข้าถึงตัวแปรสมาชิกแบบคงที่ $this
ใช้ในฟังก์ชันสมาชิกแบบไม่คงที่และเป็นการอ้างอิงถึงอินสแตนซ์ของคลาสที่เรียกใช้ฟังก์ชันสมาชิก
เนื่องจากthis
เป็นวัตถุคุณจึงใช้มันเหมือน:$this->member
เนื่องจากself
ไม่ใช่วัตถุจึงเป็นชนิดที่อ้างอิงถึงคลาสปัจจุบันโดยอัตโนมัติคุณจึงใช้มันเหมือน:self::member
$this->
ใช้เพื่ออ้างถึงอินสแตนซ์เฉพาะของตัวแปรคลาส (ตัวแปรสมาชิก) หรือวิธีการ
Example:
$derek = new Person();
$ derek ตอนนี้เป็นตัวอย่างเฉพาะของบุคคล ทุกคนมีชื่อและนามสกุลเป็นนามสกุล แต่ $ derek มีชื่อและนามสกุลเฉพาะ (ดีเร็กมาร์ติน) ภายในอินสแตนซ์ $ derek เราสามารถอ้างถึงสิ่งเหล่านี้เป็น $ this-> first_name และ $ this-> last_name
ClassName :: ใช้เพื่ออ้างถึงชนิดของคลาสนั้นและตัวแปรสแตติกวิธีการสแตติก หากช่วยได้คุณสามารถแทนที่คำว่า "คงที่" ด้วย "แบ่งปัน" ได้ เนื่องจากพวกเขาแชร์กันพวกเขาไม่สามารถอ้างถึง $ this ซึ่งอ้างถึงอินสแตนซ์เฉพาะ (ไม่แชร์) ตัวแปรแบบคงที่ (เช่น $ db_connection คงที่) สามารถใช้ร่วมกันระหว่างอินสแตนซ์ทั้งหมดของชนิดของวัตถุ ตัวอย่างเช่นวัตถุฐานข้อมูลทั้งหมดแชร์การเชื่อมต่อเดียว (การเชื่อมต่อ $ แบบคงที่)
ตัวอย่างตัวแปรแบบคงที่: แกล้งทำเป็นว่าเรามีคลาสฐานข้อมูลที่มีตัวแปรสมาชิกเดียว: $ num_connections แบบคงที่; ตอนนี้ให้ใส่ไว้ในตัวสร้าง:
function __construct()
{
if(!isset $num_connections || $num_connections==null)
{
$num_connections=0;
}
else
{
$num_connections++;
}
}
เช่นเดียวกับวัตถุที่มีคอนสตรัคเตอร์พวกเขายังมี destructors ซึ่งจะดำเนินการเมื่อวัตถุตายหรือไม่ได้ตั้งค่า:
function __destruct()
{
$num_connections--;
}
ทุกครั้งที่เราสร้างอินสแตนซ์ใหม่มันจะเพิ่มตัวนับการเชื่อมต่อของเราทีละหนึ่ง ทุกครั้งที่เราทำลายหรือหยุดการใช้อินสแตนซ์มันจะลดตัวนับการเชื่อมต่อโดยหนึ่ง ด้วยวิธีนี้เราสามารถตรวจสอบจำนวนอินสแตนซ์ของวัตถุฐานข้อมูลที่เราใช้กับ:
echo DB::num_connections;
เนื่องจาก $ num_connections เป็นแบบคงที่ (ใช้ร่วมกัน) มันจะแสดงจำนวนทั้งหมดของวัตถุฐานข้อมูลที่ใช้งานอยู่ คุณอาจเห็นเทคนิคนี้ใช้เพื่อแบ่งปันการเชื่อมต่อฐานข้อมูลระหว่างอินสแตนซ์ทั้งหมดของคลาสฐานข้อมูล สิ่งนี้เสร็จสิ้นเนื่องจากการสร้างการเชื่อมต่อฐานข้อมูลใช้เวลานานดังนั้นจึงเป็นการดีที่สุดที่จะสร้างเพียงหนึ่งรายการและใช้ร่วมกัน (ซึ่งเรียกว่ารูปแบบซิงเกิล)
วิธีการแบบคงที่ (เช่นมุมมองแบบคงที่สาธารณะ :: format_phone_number ($ หลัก)) สามารถใช้ได้โดยไม่ต้องให้อินสแตนซ์แรกของวัตถุเหล่านั้น (เช่นพวกเขาไม่ได้อ้างถึง $ this ภายใน)
ตัวอย่างวิธีการแบบคงที่:
public static function prettyName($first_name, $last_name)
{
echo ucfirst($first_name).' '.ucfirst($last_name);
}
echo Person::prettyName($derek->first_name, $derek->last_name);
อย่างที่คุณสามารถเห็นฟังก์ชั่นสาธารณะคงที่ prettyName ไม่รู้อะไรเกี่ยวกับวัตถุ เป็นเพียงการทำงานกับพารามิเตอร์ที่คุณส่งผ่านเช่นฟังก์ชั่นปกติที่ไม่ได้เป็นส่วนหนึ่งของวัตถุ ถ้าอย่างนั้นทำไมเราถึงไม่ได้มันเป็นส่วนหนึ่งของวัตถุล่ะ?
SELF :: ถ้าคุณกำลังเขียนโค้ดนอกวัตถุที่มีวิธีการคงที่ที่คุณต้องการอ้างถึงคุณต้องเรียกมันโดยใช้ชื่อของวัตถุ View :: format_phone_number ($ phone_number); หากคุณกำลังเข้ารหัสภายในวัตถุที่มีวิธีการแบบคงที่คุณต้องการที่จะอ้างถึงคุณสามารถทั้งใช้วัตถุชื่อ View :: format_phone_number ($ PN) หรือคุณสามารถใช้ตัวเอง :: format_phone_number ($ PN) ทางลัด
สิ่งเดียวกันนี้สำหรับตัวแปรแบบคงที่: ตัวอย่าง:ดู :: templates_path และ self :: templates_path
ภายในคลาส DB ถ้าเราอ้างถึงวิธีการคงที่ของวัตถุอื่น ๆ เราจะใช้ชื่อของวัตถุ: ตัวอย่าง: Session :: getUsersOnline ();
แต่ถ้าคลาส DB ต้องการอ้างถึงตัวแปรสแตติกของตัวเองมันก็จะพูดตัวเอง: ตัวอย่าง:การเชื่อมต่อด้วยตนเอง ::;
หวังว่าจะช่วยให้ชัดเจนขึ้น :)
$
เครื่องหมาย ตัวอย่างเช่นself::$templates_path
จากโพสต์บล็อกนี้ :
self
หมายถึงคลาสปัจจุบันself
สามารถใช้เรียกฟังก์ชันแบบสแตติกและอ้างอิงตัวแปรสมาชิกแบบสแตติกself
สามารถใช้ภายในฟังก์ชั่นคงที่self
ยังสามารถปิดพฤติกรรม polymorphic โดยการข้าม vtable$this
อ้างถึงวัตถุปัจจุบัน$this
สามารถใช้เรียกฟังก์ชันคงที่ได้$this
ไม่ควรใช้เพื่อเรียกตัวแปรสมาชิกแบบคงที่ ใช้self
แทน$this
ไม่สามารถใช้ภายในฟังก์ชั่นคงที่
ใน PHP คุณใช้คำสำคัญด้วยตนเองเพื่อเข้าถึงคุณสมบัติและวิธีการแบบคงที่
ปัญหาคือคุณสามารถแทนที่$this->method()
ด้วยself::method()
ที่ใดก็ได้โดยไม่คำนึงว่าmethod()
จะประกาศคงที่หรือไม่ คุณควรใช้อันไหนดี?
พิจารณารหัสนี้:
class ParentClass {
function test() {
self::who(); // will output 'parent'
$this->who(); // will output 'child'
}
function who() {
echo 'parent';
}
}
class ChildClass extends ParentClass {
function who() {
echo 'child';
}
}
$obj = new ChildClass();
$obj->test();
ในตัวอย่างนี้self::who()
จะส่งออก 'ผู้ปกครอง' เสมอในขณะที่$this->who()
จะขึ้นอยู่กับสิ่งที่วัตถุมี
ตอนนี้เราจะเห็นได้ว่าตัวเองหมายถึงระดับที่จะเรียกว่าในขณะที่$this
หมายถึงระดับของวัตถุในปัจจุบัน
ดังนั้นคุณควรใช้ตัวเองเฉพาะเมื่อ$this
ไม่พร้อมใช้งานหรือเมื่อคุณไม่ต้องการอนุญาตให้คลาสที่สืบทอดเพื่อเขียนทับวิธีปัจจุบัน
ภายในคำจำกัดความของคลาส$this
หมายถึงวัตถุปัจจุบันในขณะที่self
อ้างอิงถึงคลาสปัจจุบัน
มันเป็นสิ่งจำเป็นที่จะอ้างถึงองค์ประกอบชั้นเรียนโดยใช้และอ้างถึงองค์ประกอบวัตถุโดยใช้self
$this
self::STAT // refer to a constant value
self::$stat // static variable
$this->stat // refer to an object variable
นี่คือตัวอย่างของการใช้งาน $ this และ self สำหรับตัวแปรสมาชิกแบบไม่คงที่และแบบคงที่:
<?php
class X {
private $non_static_member = 1;
private static $static_member = 2;
function __construct() {
echo $this->non_static_member . ' '
. self::$static_member;
}
}
new X();
?>
ตามhttp://www.php.net/manual/en/language.oop5.static.php$self
ไม่มี มีเพียง$this
เพื่ออ้างอิงถึงอินสแตนซ์ปัจจุบันของคลาส (วัตถุ) และตัวเองซึ่งสามารถใช้เพื่ออ้างถึงสมาชิกแบบคงที่ของคลาส ความแตกต่างระหว่างอินสแตนซ์ของวัตถุและคลาสเข้ามาที่นี่
ClassName::staticMember
ผมเชื่อว่าคำถามไม่ได้ว่าคุณสามารถโทรหาสมาชิกแบบคงที่ของการเรียนโดยการเรียก คำถามคือสิ่งที่แตกต่างระหว่างการใช้และself::classmember
$this->classmember
ตัวอย่างเช่นทั้งสองตัวอย่างต่อไปนี้ทำงานโดยไม่มีข้อผิดพลาดไม่ว่าคุณจะใช้self::
หรือ$this->
class Person{
private $name;
private $address;
public function __construct($new_name,$new_address){
$this->name = $new_name;
$this->address = $new_address;
}
}
class Person{
private $name;
private $address;
public function __construct($new_name,$new_address){
self::$name = $new_name;
self::$address = $new_address;
}
}
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
self
หมายถึงคลาสปัจจุบัน (ซึ่งเรียกว่า)
$this
อ้างถึงวัตถุปัจจุบัน คุณสามารถใช้สแตติกแทนตนเอง ดูตัวอย่าง:
class ParentClass {
function test() {
self::which(); // output 'parent'
$this->which(); // output 'child'
}
function which() {
echo 'parent';
}
}
class ChildClass extends ParentClass {
function which() {
echo 'child';
}
}
$obj = new ChildClass();
$obj->test();
เอาท์พุท: ผู้ปกครองเด็ก
$this
ที่อ้างถึงวัตถุปัจจุบันstatic
หมายถึงวัตถุปัจจุบันself
หมายถึงคลาสที่แน่นอนที่กำหนดไว้parent
หมายถึงพาเรนต์ของคลาสที่แน่นอนที่ถูกกำหนดดูตัวอย่างต่อไปนี้ซึ่งแสดงการโอเวอร์โหลด
<?php
class A {
public static function newStaticClass()
{
return new static;
}
public static function newSelfClass()
{
return new self;
}
public function newThisClass()
{
return new $this;
}
}
class B extends A
{
public function newParentClass()
{
return new parent;
}
}
$b = new B;
var_dump($b::newStaticClass()); // B
var_dump($b::newSelfClass()); // A because self belongs to "A"
var_dump($b->newThisClass()); // B
var_dump($b->newParentClass()); // A
class C extends B
{
public static function newSelfClass()
{
return new self;
}
}
$c = new C;
var_dump($c::newStaticClass()); // C
var_dump($c::newSelfClass()); // C because self now points to "C" class
var_dump($c->newThisClass()); // C
var_dump($b->newParentClass()); // A because parent was defined *way back* in class "B"
ส่วนใหญ่เวลาที่คุณต้องการที่จะดูที่ระดับปัจจุบันซึ่งเป็นเหตุผลที่คุณใช้หรือstatic
$this
อย่างไรก็ตามมีบางครั้งที่คุณต้องการ self
เพราะคุณต้องการชั้นเรียนดั้งเดิมโดยไม่คำนึงถึงสิ่งที่ขยาย (มากไม่ค่อยมาก)
อย่างที่ไม่มีใครพูดถึงเกี่ยวกับการแสดงนี่เป็นเกณฑ์มาตรฐานขนาดเล็กที่ฉันทำ (5.6):
Name | Time | Percent
----------|---------|---------
$this-> | 0.99163 | 106.23%
self:: | 0.96912 | 103.82%
static:: | 0.93348 | 100%
นี่คือผลลัพธ์สำหรับการวิ่ง 2,000 000 และนี่คือรหัสที่ฉันใช้:
<?php
require '../vendor/autoload.php';
// My small class to do benchmarks
// All it does is looping over every test x times and record the
// time it takes using `microtime(true)`
// Then, the percentage is calculated, with 100% being the quickest
// Times are being rouned for outputting only, not to calculate the percentages
$b = new Tleb\Benchmark\Benchmark(2000000);
class Foo
{
public function calling_this()
{
$this->called();
}
public function calling_self()
{
self::called();
}
public function calling_static()
{
static::called();
}
public static function called()
{
}
}
$b->add('$this->', function () { $foo = new Foo; $foo->calling_this(); });
$b->add('self::', function () { $foo = new Foo; $foo->calling_self(); });
$b->add('static::', function () { $foo = new Foo; $foo->calling_static(); });
$b->run();
1 / 2e9 s = 0.5 ns
วันนี้
use
คำหลัก tbh แต่ฉันไม่มี PHP อีกต่อไปที่จะทำซ้ำมาตรฐานและฉันไม่รู้สึกอยากติดตั้งใหม่
เมื่อself
ใช้กับ::
โอเปอเรเตอร์มันหมายถึงคลาสปัจจุบันซึ่งสามารถทำได้ทั้งในบริบทคงที่และไม่คงที่ $this
หมายถึงวัตถุนั้นเอง นอกจากนี้มันเป็นกฎหมายที่สมบูรณ์แบบที่จะใช้$this
เพื่อเรียกวิธีการคงที่ (แต่ไม่ได้อ้างถึงเขตข้อมูล)
ฉันพบคำถามเดียวกันและคำตอบง่ายๆคือ:
$this
ต้องการอินสแตนซ์ของคลาสself::
ไม่เมื่อใดก็ตามที่คุณกำลังใช้วิธีการคงที่หรือแอตทริบิวต์คงที่และต้องการที่จะเรียกพวกเขาโดยไม่ต้องมีวัตถุของชั้นเรียนยกตัวอย่างคุณจะต้องใช้self:
ในการเรียกพวกเขาเพราะ$this
ต้องสร้างบนวัตถุเสมอ
$this
หมายถึงวัตถุชั้นปัจจุบัน self
หมายถึงคลาสปัจจุบัน (ไม่ใช่วัตถุ) คลาสเป็นพิมพ์เขียวของวัตถุ ดังนั้นคุณจึงกำหนดคลาส แต่คุณสร้างวัตถุ
ดังนั้นในคำอื่น ๆ ที่ใช้งานและself for static
this for none-static members or methods
ในสถานการณ์ที่เด็ก / ผู้ปกครองself / parent
ส่วนใหญ่จะใช้เพื่อระบุเด็กและผู้ปกครองสมาชิกระดับและวิธีการ
นอกจากนี้ตั้งแต่$this::
ยังไม่ได้พูดคุย
เพื่อจุดประสงค์ในการให้ข้อมูลเท่านั้น PHP 5.3 เมื่อจัดการกับออบเจ็กต์อินสแตนซ์เพื่อรับค่าขอบเขตปัจจุบันซึ่งต่างจากการใช้static::
งานคุณสามารถเลือกใช้$this::
เช่นนั้นได้
class Foo
{
const NAME = 'Foo';
//Always Foo::NAME (Foo) due to self
protected static $staticName = self::NAME;
public function __construct()
{
echo $this::NAME;
}
public function getStaticName()
{
echo $this::$staticName;
}
}
class Bar extends Foo
{
const NAME = 'FooBar';
/**
* override getStaticName to output Bar::NAME
*/
public function getStaticName()
{
$this::$staticName = $this::NAME;
parent::getStaticName();
}
}
$foo = new Foo; //outputs Foo
$bar = new Bar; //outputs FooBar
$foo->getStaticName(); //outputs Foo
$bar->getStaticName(); //outputs FooBar
$foo->getStaticName(); //outputs FooBar
การใช้รหัสด้านบนไม่ใช่วิธีการทั่วไปหรือวิธีปฏิบัติที่แนะนำ แต่เป็นเพียงเพื่อแสดงให้เห็นถึงการใช้งานและเป็นหน้าที่ของ "คุณรู้หรือไม่" ตามคำถามของผู้โพสต์ดั้งเดิม
นอกจากนี้ยังแสดงถึงการใช้$object::CONSTANT
ตัวอย่างเช่นecho $foo::NAME;
เมื่อเทียบกับ$this::NAME;
ใช้self
ถ้าคุณต้องการเรียกเมธอดของคลาสโดยไม่สร้างวัตถุ / อินสแตนซ์ของคลาสนั้นดังนั้นจึงช่วยประหยัดRAM (บางครั้งใช้ตัวเองเพื่อจุดประสงค์นั้น) กล่าวอีกนัยหนึ่งมันคือการเรียกวิธีการแบบสแตติก ใช้this
สำหรับมุมมองวัตถุ
กรณีที่ 1: การใช้self
สามารถใช้สำหรับค่าคงที่คลาสได้
คลาส classA { const FIXED_NUMBER = 4; ตนเอง :: POUNDS_TO_KILOGRAMS }
ถ้าคุณต้องการโทรหามันนอกห้องเรียนใช้classA::POUNDS_TO_KILOGRAMS
เพื่อเข้าถึงค่าคงที่
กรณีที่ 2: สำหรับคุณสมบัติคงที่
คลาส classC { ฟังก์ชั่นสาธารณะ __ โครงสร้าง () { ตนเอง :: _ $ เคาน์เตอร์ ++; $ this-> num = self :: $ _ counter; } }
ตาม php.net มีสามคำพิเศษในบริบทนี้: self
, และparent
static
พวกมันถูกใช้เพื่อเข้าถึงคุณสมบัติหรือเมธอดจากภายในนิยามคลาส
$this
ในทางตรงกันข้ามจะใช้ในการเรียกตัวอย่างและวิธีการของชั้นเรียนใด ๆ ตราบเท่าที่ชั้นนั้นสามารถเข้าถึงได้
คำหลักself :: ที่ใช้สำหรับคลาสปัจจุบันและโดยทั่วไปจะใช้เพื่อเข้าถึงสมาชิกแบบคงที่วิธีการและค่าคงที่ แต่ในกรณีของ$ นี่คุณไม่สามารถเรียกสมาชิกแบบคงที่วิธีการและฟังก์ชั่น
คุณสามารถใช้คำสำคัญself ::ในชั้นเรียนอื่นและเข้าถึงสมาชิกคงที่วิธีการและค่าคงที่ เมื่อมันจะถูกขยายจากระดับผู้ปกครองและเหมือนกันในกรณีของ$คำหลักนี้ คุณสามารถเข้าถึงสมาชิกที่ไม่คงที่วิธีการและฟังก์ชั่นในชั้นเรียนอื่นเมื่อมันจะถูกขยายจากชั้นผู้ปกครอง
รหัสที่ระบุด้านล่างเป็นตัวอย่างของตัวเอง ::และ$คำหลักนี้ เพียงคัดลอกและวางรหัสในไฟล์รหัสของคุณและดูผลลัพธ์
class cars{
var $doors=4;
static $car_wheel=4;
public function car_features(){
echo $this->doors." Doors <br>";
echo self::$car_wheel." Wheels <br>";
}
}
class spec extends cars{
function car_spec(){
print(self::$car_wheel." Doors <br>");
print($this->doors." Wheels <br>");
}
}
/********Parent class output*********/
$car = new cars;
print_r($car->car_features());
echo "------------------------<br>";
/********Extend class from another class output**********/
$car_spec_show=new spec;
print($car_spec_show->car_spec());