ใน 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 XX::foo()ถ้าวัตถุเป็นของมันเรียกtype YY::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 staticthis 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());