Câu hỏi Khi nào sử dụng bản thân trên $ này?


Trong PHP 5, sự khác biệt giữa việc sử dụng self và $this?

Khi nào thì thích hợp?


1777
2017-09-30 06:23


gốc


có thể trùng lặp Mới tự so với tĩnh mới - Orangepill
Tôi sẽ hỏi what'is sự khác biệt giữa: cont A; $ this-> A và self :: A - mboullouz


Các câu trả lời:


Câu trả lời ngắn

Sử dụng $this để tham khảo hiện tại   vật. Sử dụng self để tham khảo   lớp hiện tại. Nói cách khác, sử dụng    $this->member cho các thành viên không tĩnh,   sử dụng self::$member cho các thành viên tĩnh.

Trả lời đầy đủ

Đây là một ví dụ về chính xác sử dụng $this và self cho các biến thành viên không tĩnh và tĩnh:

<?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();
?>

Đây là một ví dụ về sai sử dụng $this và self cho các biến thành viên không tĩnh và tĩnh:

<?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();
?>

Đây là một ví dụ về đa hình với $this cho các hàm thành viên:

<?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();
?>

Đây là một ví dụ về đàn áp hành vi đa hình bằng cách sử dụng self cho các hàm thành viên:

<?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();
?>

Ý tưởng là $this->foo() gọi foo() chức năng thành viên của bất cứ điều gì> là loại chính xác của đối tượng hiện tại. Nếu đối tượng là type X, do đó,> cuộc gọi X::foo(). Nếu đối tượng là type Y, Nó gọi Y::foo(). Nhưng với> self :: foo (), X::foo() luôn được gọi.

Từ http://www.phpbuilder.com/board/showthread.php?t=10354489:

Bởi http://board.phpbuilder.com/member.php?145249-laserlight


1512
2017-09-30 06:29



Câu trả lời này quá đơn giản. Như đã chỉ ra trong các câu trả lời khác, self được sử dụng với toán tử phân giải phạm vi :: để tham khảo lớp hiện tại; điều này có thể được thực hiện cả trong bối cảnh tĩnh và không tĩnh. Ngoài ra, nó hoàn toàn hợp pháp để sử dụng $this để gọi các phương thức tĩnh (nhưng không gọi các trường tham chiếu). - Artefacto
Cũng nên xem xét sử dụng static :: thay vì :: self nếu bạn đang trên 5.3+. Nó có thể gây ra bạn đau đầu không được kể ra khác, xem câu trả lời của tôi dưới đây cho lý do tại sao. - Sqoo
-1. Câu trả lời này là gây hiểu lầm, đọc các câu trả lời khác để biết thêm thông tin. - Pacerier
Nó có thể được đơn giản hóa quá mức, nhưng nó đã trả lời câu hỏi cấp cơ bản của tôi mà không làm cho đầu tôi phát nổ. Tôi đã nhận được một số thông tin thêm mà tôi thấy hữu ích hơn nữa xuống, nhưng bây giờ tôi chỉ cố gắng tìm ra lý do tại sao tôi nhấn thuộc tính lớp của tôi với $ this-> attrib và hằng số lớp với self :: constant. Điều này đã giúp tôi hiểu rằng tốt hơn - MydKnight
Thế còn $this::? - James


Từ khóa tự thực hiện KHÔNG PHẢI chỉ tham chiếu đến 'lớp học hiện tại', ít nhất không theo cách hạn chế bạn với các thành viên tĩnh. Trong bối cảnh của một thành viên không tĩnh, self cũng cung cấp cách bỏ qua vtable (xem wiki trên vtable) cho đối tượng hiện tại. Cũng như bạn có thể sử dụng parent::methodName() để gọi phiên bản cha mẹ của một hàm, vì vậy bạn có thể gọi self::methodName() để gọi các lớp hiện tại đang thực hiện một phương thức.

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();

Điều này sẽ xuất:

Xin chào, tôi là Ludwig geek
     Tạm biệt Ludwig người

sayHello() sử dụng $this con trỏ, vì vậy vtable được gọi để gọi Geek::getTitle(). sayGoodbye() sử dụng self::getTitle(), do đó, vtable không được sử dụng và Person::getTitle() được gọi là. Trong cả hai trường hợp, chúng ta đang xử lý phương thức của một đối tượng instantiated và có quyền truy cập vào $this con trỏ trong các hàm được gọi.


710
2017-07-27 18:00



Câu trả lời này sẽ tốt hơn nếu bạn bắt đầu với một quy tắc chung thay vì một ngoại lệ. Đó là vấn đề về phong cách, không phải về chuyên môn kỹ thuật. Đây là ví dụ tốt nhất mà tôi từng thấy về sự khác biệt giữa bản thân :: và $ this->, nhưng thật đáng tiếc khi che giấu điều đó bằng cách bác bỏ một khái niệm trước. - adjwilli
@adjwilli: Tại sao kiểu xấu đó? Nó không nâng cao ý thức nếu kỳ vọng (luận án) của OP lần đầu tiên bị từ chối (phản đối) và sau đó giải thích được đưa ra như là tổng hợp? - hakre
Tôi thấy "lớp học hiện tại" thực sự có vấn đề. Vì sự kết hợp từ đó có thể được hiểu là cả hai "lớp học self được đặt "/" định nghĩa lớp, nó là một phần chữ của "cũng như" lớp của đối tượng "(mà thực sự sẽ là static). - Jakumi
Thế còn $this::? - James


KHÔNG ĐƯỢC DÙNG self::, sử dụng static::

Có một khía cạnh khác của bản thân :: điều đáng nói đến. Bực bội self:: đề cập đến phạm vi tại điểm định nghĩa không phải tại thời điểm thực hiện. Hãy xem xét lớp đơn giản này với hai phương thức:

class Person
{

    public static function status()
    {
        self::getStatus();
    }

    protected static function getStatus()
    {
        echo "Person is alive";
    }

}

Nếu chúng ta gọi Person::status() chúng ta sẽ thấy "Người còn sống". Bây giờ hãy xem xét điều gì xảy ra khi chúng ta tạo ra một lớp kế thừa từ điều này:

class Deceased extends Person
{

    protected static function getStatus()
    {
        echo "Person is deceased";
    }

}

Đang gọi Deceased::status() chúng tôi hy vọng sẽ thấy "Người đã qua đời" tuy nhiên những gì chúng ta thấy là "Người còn sống" vì phạm vi chứa định nghĩa phương thức ban đầu khi gọi đến self::getStatus() Đã được định nghĩa.

PHP 5.3 có một giải pháp. các static:: nhà điều hành độ phân giải thực hiện "ràng buộc tĩnh muộn", đó là một cách ưa thích để nói rằng nó bị ràng buộc với phạm vi của lớp được gọi. Thay đổi dòng trong status() đến static::getStatus() và kết quả là những gì bạn mong đợi. Trong các phiên bản PHP cũ hơn, bạn sẽ phải tìm một kludge để làm điều này.

Xem Tài liệu PHP

Vì vậy, để trả lời câu hỏi không được hỏi ...

$this-> đề cập đến đối tượng hiện tại (một thể hiện của một lớp), trong khi static::đề cập đến một lớp


429
2017-07-24 15:08



Điều gì về các hằng số lớp? - Kevin Bond
Tôi đoán cũng vậy - Sqoo
"Calling Deceased :: status () chúng ta sẽ thấy" Person is deadeased "". Không. Đây là một cuộc gọi hàm tĩnh nên không có sự đa hình nào liên quan. - cquezel
@jasondavis cảm ơn, tôi đã cố gắng sử dụng tiếng Anh và tránh các thuật ngữ như đa hình. Câu trả lời này thường được đặt theo thuật ngữ chỉ có một nhà khoa học máy tính hiểu được, PHP không phải là ngôn ngữ nhằm vào các nhà khoa học máy tính! - Sqoo
Ví dụ có vẻ khó hiểu với tôi: Tôi thấy getStatus phương thức như tôi sẽ gọi cho một cá thể lớp, không phải cho một lớp. - Jānis Elmeris


Để thực sự hiểu những gì chúng ta đang nói về khi chúng ta nói về self đấu với $this, chúng ta cần phải thực sự tìm hiểu những gì đang xảy ra ở mức độ khái niệm và thực tế. Tôi không thực sự cảm thấy bất kỳ câu trả lời nào làm điều này một cách thích hợp, vì vậy đây là nỗ lực của tôi.

Hãy bắt đầu bằng cách nói về những gì lớp học và một vật Là.

Lớp và đối tượng, khái niệm

Vì vậy, những gì  một lớp học? Rất nhiều người định nghĩa nó như là một bản vẽ thiết kế hoặc một bản mẫu cho một đối tượng. Trong thực tế, bạn có thể đọc thêm Giới thiệu về lớp học bằng PHP tại đây. Và ở một mức độ nào đó thực sự là nó. Hãy xem một lớp học:

class Person {
    public $name = 'my name';
    public function sayHello() {
        echo "Hello";
    }
}

Như bạn có thể nói, có một thuộc tính trong lớp đó được gọi là $name và một phương thức (hàm) được gọi là sayHello().

nó là rất quan trọng cần lưu ý là lớp học là một cấu trúc tĩnh. Điều đó có nghĩa là lớp học Person, một khi được định nghĩa, luôn giống nhau ở mọi nơi bạn nhìn vào nó.

Mặt khác, đối tượng được gọi là ví dụ của một lớp. Điều đó có nghĩa là chúng tôi lấy "bản thiết kế" của lớp và sử dụng nó để tạo bản sao động. Bản sao này hiện được liên kết cụ thể với biến được lưu trữ. Vì vậy, mọi thay đổi đối với một ví dụ là cục bộ cho cá thể đó.

$bob = new Person;
$adam = new Person;
$bob->name = 'Bob';
echo $adam->name; // "my name"

Chúng tôi tạo mới các phiên bản của một lớp bằng cách sử dụng new nhà điều hành.

Vì vậy, chúng ta nói rằng một Class là một cấu trúc toàn cầu, và một Object là một cấu trúc cục bộ. Đừng lo lắng về điều đó buồn cười -> cú pháp, chúng ta sẽ đi vào đó một chút.

Một điều khác chúng ta nên nói đến, là chúng ta có thể kiểm tra nếu một thể hiện là một instanceof một lớp học cụ thể: $bob instanceof Person trả về một boolean nếu $bob ví dụ đã được thực hiện bằng cách sử dụng Person lớp học, hoặc là một đứa trẻ Person.

Xác định trạng thái

Vì vậy, chúng ta hãy đào một chút vào những gì một lớp thực sự chứa. Có 5 loại "thứ" mà một lớp chứa:

  1. Tính chất - Hãy nghĩ về những biến này mà mỗi cá thể sẽ chứa.

    class Foo {
        public $bar = 1;
    }
    
  2. Thuộc tính tĩnh - Hãy nghĩ về những biến này được chia sẻ ở cấp lớp. Có nghĩa là chúng không bao giờ được sao chép bởi mỗi cá thể.

    class Foo {
        public static $bar = 1;
    }
    
  3. Phương pháp - Đây là các hàm mà mỗi cá thể sẽ chứa (và hoạt động trên các cá thể).

    class Foo {
        public function bar() {}
    }
    
  4. Phương pháp tĩnh - Đây là những chức năng được chia sẻ trên toàn bộ lớp học. Họ làm không phải hoạt động trên các cá thể, nhưng thay vào đó chỉ trên các thuộc tính tĩnh.

    class Foo {
        public static function bar() {}
    }
    
  5. Hằng số - Lớp được giải quyết hằng số. Không đi sâu hơn ở đây, nhưng thêm cho đầy đủ:

    class Foo {
        const BAR = 1;
    }
    

Vì vậy, về cơ bản, chúng tôi đang lưu trữ thông tin về lớp và đối tượng chứa bằng cách sử dụng "gợi ý" về tĩnh xác định xem thông tin được chia sẻ (và do đó tĩnh) hay không (và do đó năng động).

Nhà nước và phương pháp

Bên trong của một phương thức, một cá thể của đối tượng được biểu diễn bởi $thisbiến. Trạng thái hiện tại của đối tượng đó là ở đó, và biến đổi (thay đổi) bất kỳ thuộc tính nào sẽ dẫn đến thay đổi đối với cá thể đó (nhưng không phải là các đối tượng khác).

Nếu một phương thức được gọi là tĩnh, $this biến không được định nghĩa. Điều này là do không có cá thể nào được kết hợp với một cuộc gọi tĩnh.

Điều thú vị ở đây là làm thế nào các cuộc gọi tĩnh được thực hiện. Vì vậy, hãy nói về cách chúng ta truy cập vào trạng thái:

Trạng thái truy cập

Bây giờ chúng ta đã lưu trữ trạng thái đó, chúng ta cần truy cập nó. Điều này có thể hơi phức tạp (hoặc đường nhiều hơn một chút), vì vậy hãy chia thành hai điểm nhìn: từ bên ngoài một cá thể / lớp (nói từ một cuộc gọi hàm bình thường, hoặc từ phạm vi toàn cục), và bên trong một cá thể / lớp (từ bên trong một phương thức trên vật).

Từ bên ngoài trường hợp / lớp học

Từ bên ngoài của một thể hiện / lớp, các quy tắc của chúng ta khá đơn giản và có thể dự đoán được. Chúng ta có hai toán tử, và mỗi toán tử cho chúng ta biết ngay lập tức nếu chúng ta đang xử lý một cá thể hoặc một lớp tĩnh:

  • -> - - toán tử đối tượng - Điều này luôn được sử dụng khi chúng ta truy cập một cá thể.

    $bob = new Person;
    echo $bob->name;
    

    Điều quan trọng cần lưu ý là gọi điện Person->foo không có ý nghĩa (kể từ Person là một lớp, không phải là một thể hiện). Do đó, đó là lỗi phân tích cú pháp.

  • :: - - -nhà điều hành độ phân giải - Điều này luôn được sử dụng để truy cập thuộc tính hoặc phương thức tĩnh Lớp.

    echo Foo::bar()
    

    Ngoài ra, chúng ta có thể gọi một phương thức tĩnh trên một đối tượng theo cùng một cách:

    echo $foo::bar()
    

    nó là vô cùng điều quan trọng cần lưu ý là khi chúng ta làm điều này từ bên ngoài, đối tượng của đối tượng bị ẩn khỏi bar() phương pháp. Có nghĩa là nó chính xác giống như chạy:

    $class = get_class($foo);
    $class::bar();
    

Vì thế, $this không được định nghĩa trong cuộc gọi tĩnh.

Từ bên trong của một cá thể / lớp

Mọi thứ thay đổi một chút ở đây. Các toán tử giống nhau được sử dụng, nhưng ý nghĩa của chúng trở nên mờ nhạt đáng kể.

Các toán tử đối tượng  -> vẫn được sử dụng để thực hiện cuộc gọi đến trạng thái cá thể của đối tượng.

class Foo {
    public $a = 1;
    public function bar() {
        return $this->a;
    }
}

Gọi điện cho bar() phương pháp trên $foo (một ví dụ của Foo) bằng cách sử dụng toán tử đối tượng: $foo->bar() sẽ dẫn đến phiên bản của cá thể $a.

Vì vậy, đó là cách chúng tôi mong đợi.

Ý nghĩa của :: nhà điều hành mặc dù thay đổi. Nó phụ thuộc vào ngữ cảnh của cuộc gọi đến hàm hiện tại:

  • Trong một bối cảnh tĩnh

    Trong ngữ cảnh tĩnh, mọi cuộc gọi được thực hiện bằng :: cũng sẽ tĩnh. Hãy xem một ví dụ:

    class Foo {
        public function bar() {
            return Foo::baz();
        }
        public function baz() {
            return isset($this);
        }
    }
    

    Đang gọi Foo::bar() sẽ gọi baz() phương pháp tĩnh và do đó $this sẽ không phải được dân cư. Cần lưu ý rằng trong các phiên bản PHP gần đây (5.3+), điều này sẽ kích hoạt E_STRICT lỗi, bởi vì chúng ta đang gọi các phương thức tĩnh không tĩnh.

  • Trong một ngữ cảnh cá thể

    Trong một bối cảnh ví dụ, mặt khác, các cuộc gọi được thực hiện bằng cách sử dụng :: phụ thuộc vào người nhận cuộc gọi (phương thức mà chúng tôi đang gọi). Nếu phương thức được định nghĩa là static, sau đó nó sẽ sử dụng một cuộc gọi tĩnh. Nếu không, nó sẽ chuyển tiếp thông tin cá thể.

    Vì vậy, nhìn vào mã trên, gọi $foo->bar() sẽ trở lại true, vì cuộc gọi "tĩnh" xảy ra bên trong ngữ cảnh cá thể.

Có lý? Không nghĩ vậy. Thật khó hiểu.

Từ khóa cắt ngắn

Bởi vì buộc tất cả mọi thứ với nhau bằng cách sử dụng tên lớp là khá bẩn, PHP cung cấp 3 từ khóa "shortcut" cơ bản để làm cho phạm vi giải quyết dễ dàng hơn.

  • self - Điều này đề cập đến tên lớp hiện tại. Vì thế self::baz() giống như Foo::baz() trong Foo lớp (mọi phương thức trên đó).

  • parent - Điều này nói đến phụ huynh của lớp hiện tại.

  • static - Điều này đề cập đến lớp được gọi. Nhờ thừa kế, các lớp con có thể ghi đè lên các phương thức và các thuộc tính tĩnh. Vì vậy, gọi cho họ bằng cách sử dụng static thay vì tên lớp cho phép chúng tôi giải quyết cuộc gọi đến từ đâu, thay vì cấp độ hiện tại.

Ví dụ

Cách dễ nhất để hiểu điều này là bắt đầu xem xét một số ví dụ. Hãy chọn một lớp học:

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();
    }
}

Bây giờ, chúng ta cũng đang tìm kiếm thừa kế ở đây. Bỏ qua một lúc rằng đây là một mô hình đối tượng xấu, nhưng hãy nhìn vào những gì xảy ra khi chúng ta chơi với điều này:

$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

Vì vậy, bộ đếm ID được chia sẻ trên cả hai trường hợp và trẻ em (vì chúng tôi đang sử dụng self để truy cập nó. Nếu chúng ta sử dụng static, chúng ta có thể ghi đè lên nó trong một lớp trẻ em).

var_dump($bob->getName()); // Bob
var_dump($adam->getName()); // Adam
var_dump($billy->getName()); // child: Billy

Lưu ý rằng chúng tôi đang thực hiện Person::getName()  ví dụ phương pháp mỗi lần. Nhưng chúng tôi đang sử dụng parent::getName() để làm điều đó trong một trong các trường hợp (trường hợp con). Đây là những gì làm cho cách tiếp cận này mạnh mẽ.

Lời cảnh cáo # 1

Lưu ý rằng ngữ cảnh gọi là điều xác định nếu một cá thể được sử dụng. Vì thế:

class Foo {
    public function isFoo() {
        return $this instanceof Foo;
    }
}

Không phải là luôn luôn thật.

class Bar {
    public function doSomething() {
        return Foo::isFoo();
    }
}
$b = new Bar;
var_dump($b->doSomething()); // bool(false)

Bây giờ thì đúng là vậy có thật không lạ ở đây Chúng tôi gọi một lớp khác, nhưng $this được chuyển đến Foo::isFoo() phương pháp là trường hợp của $bar.

Điều này có thể gây ra tất cả các loại lỗi và khái niệm WTF-ery. Vì vậy, tôi rất khuyên bạn nên tránh :: toán tử từ bên trong các phương thức ví dụ trên bất kỳ thứ gì ngoại trừ ba từ khóa "cắt ngắn" ảo đó (static, selfparent).

Lời cảnh cáo # 2

Lưu ý rằng các phương thức và thuộc tính tĩnh được chia sẻ bởi tất cả mọi người. Điều đó làm cho chúng về cơ bản các biến toàn cục. Với tất cả các vấn đề tương tự đi kèm với globals. Vì vậy, tôi sẽ thực sự do dự để lưu trữ thông tin trong các phương pháp tĩnh / tài sản trừ khi bạn cảm thấy thoải mái với nó là thực sự toàn cầu.

Lời cảnh cáo # 3

Nói chung, bạn sẽ muốn sử dụng những gì được gọi là Late-Static-Binding bằng cách sử dụng static thay vì self. Nhưng lưu ý rằng chúng không giống nhau, vì vậy hãy nói "luôn sử dụng static thay vì self thực sự bị cận thị. Thay vào đó, hãy dừng lại và suy nghĩ về cuộc gọi bạn muốn thực hiện và suy nghĩ xem bạn có muốn các lớp con có thể ghi đè lên tĩnh giải quyết gọi điện.

TL / DR

Quá tệ, quay lại và đọc nó. Nó có thể là quá dài, nhưng nó là dài vì đây là một chủ đề phức tạp

TL / DR # 2

Ok, được rồi. Nói ngắn gọn, self được sử dụng để tham khảo tên lớp hiện tạitrong một lớp học, ở đâu $this đề cập đến đối tượng hiện tại ví dụ. Lưu ý rằng self là một bản sao / dán cắt ngắn. Bạn có thể thay thế nó một cách an toàn bằng tên lớp của bạn và nó sẽ hoạt động tốt. Nhưng $this là một biến động mà không thể được xác định trước thời hạn (và thậm chí không thể là lớp của bạn).

TL / DR # 3

Nếu toán tử đối tượng được sử dụng (->), sau đó bạn luôn luôn biết bạn đang đối phó với một ví dụ. Nếu toán tử phân giải phạm vi được sử dụng (::), bạn cần thêm thông tin về ngữ cảnh (chúng ta đang ở trong một ngữ cảnh đối tượng chưa? Chúng ta có nằm ngoài một đối tượng không?).


228
2018-06-10 15:21



Lời cảnh cáo # 1: $ này sẽ không được định nghĩa khi gọi một phương thức tĩnh: 3v4l.org/9kr0e - Mark Achée
Tốt... $this sẽ không được xác định nếu bạn tuân thủ "Tiêu chuẩn nghiêm ngặt" và không gọi phương thức tĩnh mà không được định nghĩa là tĩnh. Tôi thấy kết quả bạn đã giải thích ở đây: 3v4l.org/WeHVM Đồng ý, thực sự kỳ lạ. - Mark Achée
Sau khi đọc xong phần mô tả dài, tôi cảm thấy lười biếng để cuộn lên trên một lần nữa để upvote nó. Chỉ đùa thôi, tôi đã upvote nó: D. Cảm ơn điều này rất hữu ích. - Mr_Green
sẽ là tốt đẹp để thêm một lời giải thích rõ ràng về sự khác biệt giữa tự :: $ tài sản và tự :: tài sản; Tôi nghĩ rằng điều đó khá khó hiểu - Tommaso Barbugli
WoC # 1 cư xử khác kể từ PHP 7. As Foo::isFoo() được gọi là tĩnh, $this sẽ không được xác định. Đó là hành vi trực quan hơn trong quan điểm của tôi. -- Khác kết quả khác được đưa ra nếu Bar đã được mở rộng từ Foo. Sau đó, cuộc gọi Foo::isFoo() sẽ thực sự nằm trong ngữ cảnh cá thể (không cụ thể cho PHP7). - Kontrollfreak


self (không phải $ tự) đề cập đến kiểu của lớp, ở đâu $this đề cập đến hiện tại ví dụ của lớp. self là để sử dụng trong các hàm thành viên tĩnh để cho phép bạn truy cập các biến thành viên tĩnh. $this được sử dụng trong các hàm thành viên không tĩnh và là tham chiếu đến cá thể của lớp mà hàm thành viên được gọi.

Bởi vì this là một đối tượng, bạn sử dụng nó như: $this->member

Bởi vì self không phải là một đối tượng, về cơ bản nó là một kiểu tự động tham chiếu đến lớp hiện tại, bạn sử dụng nó như sau: self::member


109
2017-09-30 07:26





$this-> được sử dụng để chỉ một trường hợp cụ thể của các biến của một lớp (các biến thành viên) hoặc các phương thức.

Example: 
$derek = new Person();

$ derek hiện là một cá thể cụ thể của Person. Mỗi người có một first_name và một last_name, nhưng $ derek có một tên cụ thể và last_name (Derek Martin). Bên trong trường hợp $ derek, chúng ta có thể tham chiếu đến $ $-> first_name và $ this-> last_name

ClassName :: được sử dụng để chỉ loại đó của lớp, và các biến tĩnh của nó, các phương thức tĩnh. Nếu nó giúp, bạn có thể thay thế từ "tĩnh" thành "chia sẻ". Bởi vì chúng được chia sẻ, chúng không thể tham chiếu đến $ this, trong đó đề cập đến một cá thể cụ thể (không được chia sẻ). Biến tĩnh (tức là $ db_connection tĩnh) có thể được chia sẻ giữa tất cả các trường hợp của một loại đối tượng. Ví dụ, tất cả các đối tượng cơ sở dữ liệu chia sẻ một kết nối duy nhất (kết nối $ tĩnh).

Ví dụ biến tĩnh: Giả sử chúng ta có một lớp cơ sở dữ liệu với một biến thành viên: static $ num_connections; Bây giờ, đặt cái này vào hàm tạo:

function __construct()
{
    if(!isset $num_connections || $num_connections==null)
    {
        $num_connections=0;
    }
    else
    {
        $num_connections++;
    }
}

Cũng giống như các đối tượng có các hàm tạo, chúng cũng có các hàm hủy, được thực hiện khi đối tượng chết hoặc không được đặt:

function __destruct()
{
    $num_connections--;
}

Mỗi khi chúng ta tạo một thể hiện mới, nó sẽ tăng số lượt truy cập kết nối của chúng ta lên một. Mỗi khi chúng ta phá hủy hoặc ngừng sử dụng một thể hiện, nó sẽ làm giảm số lần truy cập kết nối. Theo cách này, chúng ta có thể theo dõi số lượng cá thể của đối tượng cơ sở dữ liệu mà chúng ta đã sử dụng với:

echo DB::num_connections;

Bởi vì $ num_connections là tĩnh (được chia sẻ), nó sẽ phản ánh tổng số đối tượng cơ sở dữ liệu đang hoạt động. Bạn có thể đã thấy kỹ thuật này được sử dụng để chia sẻ các kết nối cơ sở dữ liệu trong tất cả các trường hợp của một lớp cơ sở dữ liệu. Điều này được thực hiện vì việc tạo kết nối cơ sở dữ liệu mất một thời gian dài, vì vậy tốt nhất bạn nên tạo một kết nối và chia sẻ nó (đây được gọi là Mẫu Singleton).

Phương thức tĩnh (tức là chế độ xem công khai tĩnh :: format_phone_number ($ digits)) có thể được sử dụng KHÔNG phát hiện ra một trong những đối tượng đó trước tiên (nghĩa là chúng không tham chiếu nội bộ đến $ this).

Ví dụ phương pháp tĩnh:

public static function prettyName($first_name, $last_name)
{
    echo ucfirst($first_name).' '.ucfirst($last_name);
}

echo Person::prettyName($derek->first_name, $derek->last_name);

Như bạn có thể thấy, hàm static public public prettyName không biết gì về đối tượng. Nó chỉ hoạt động với các tham số mà bạn truyền vào, như một hàm bình thường không phải là một phần của một đối tượng. Tại sao bận tâm, sau đó, nếu chúng ta chỉ có thể có nó không phải là một phần của đối tượng?

  1. Đầu tiên, việc gắn các hàm vào các đối tượng giúp bạn giữ cho mọi thứ được sắp xếp, vì vậy bạn biết nơi tìm chúng.
  2. Thứ hai, nó ngăn chặn xung đột đặt tên. Trong một dự án lớn, bạn có thể có hai nhà phát triển tạo các hàm getName (). Nếu một người tạo ra một ClassName1 :: getName (), và cái kia tạo ClassName2 :: getName (), thì không có vấn đề gì cả. Không có xung đột. Yay phương pháp tĩnh!

SELF :: Nếu bạn đang viết mã ở ngoài đối tượng có phương thức tĩnh mà bạn muốn tham chiếu, bạn phải gọi nó bằng tên của đối tượng View :: format_phone_number ($ phone_number); Nếu bạn đang viết mã phía trong đối tượng có phương pháp tĩnh bạn muốn tham chiếu, bạn có thể hoặc sử dụng tên của đối tượng View :: format_phone_number ($ pn), HOẶC bạn có thể sử dụng phím tắt tự :: format_phone_number ($ pn)

Cũng vậy với các biến tĩnh: Thí dụ: Chế độ xem :: templates_path so với self :: templates_path

Bên trong lớp DB, nếu chúng ta đề cập đến một phương thức tĩnh của một số đối tượng khác, chúng ta sẽ sử dụng tên của đối tượng: Thí dụ: Phiên :: getUsersOnline ();

Nhưng nếu lớp DB muốn tham chiếu đến biến tĩnh của riêng nó, nó sẽ tự nói: Thí dụ: self :: connection;

Hy vọng rằng sẽ giúp mọi thứ rõ ràng lên :)


93
2017-10-22 17:52



Bạn đã có $ ronny trong đoạn văn thứ hai của bạn, nhưng trừ khi tôi nhầm là lẽ ra phải là $ derek. - James Skemp
Câu trả lời chính xác. Tôi chỉ muốn chỉ ra, khi đề cập đến thuộc tính tĩnh, bạn cần sử dụng $ ký tên. Ví dụ self::$templates_path - henrywright


Từ bài đăng trên blog này:

  • self đề cập đến lớp hiện tại
  • self có thể được sử dụng để gọi các hàm tĩnh và tham chiếu các biến thành viên tĩnh
  • self có thể được sử dụng bên trong các hàm tĩnh
  • self cũng có thể tắt hành vi đa hình bằng cách bỏ qua vtable
  • $this đề cập đến đối tượng hiện tại
  • $this có thể được sử dụng để gọi các hàm tĩnh
  • $this không nên được sử dụng để gọi các biến thành viên tĩnh. Sử dụng self thay thế.
  • $this không thể được sử dụng bên trong các hàm tĩnh

27
2018-05-10 12:00





Trong PHP, bạn sử dụng từ khóa tự để truy cập các thuộc tính và phương thức tĩnh.

Vấn đề là bạn có thể thay thế $this->method() với self::method()bất cứ nơi nào, bất kể nếu method() được khai báo tĩnh hay không. Vậy bạn nên sử dụng cái nào?

Hãy xem xét mã này:

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();

Trong ví dụ này, self::who() sẽ luôn xuất ‘parent’, trong khi $this->who() sẽ phụ thuộc vào lớp mà đối tượng có.

Bây giờ chúng ta có thể thấy rằng tự đề cập đến lớp mà nó được gọi, trong khi $this đề cập đến lớp của đối tượng hiện tại.

Vì vậy, bạn nên sử dụng tự chỉ khi $this không có sẵn hoặc khi bạn không muốn cho phép các lớp con cháu ghi đè phương pháp hiện tại.


23
2017-12-29 13:20





Bên trong một định nghĩa lớp, $ này đề cập đến đối tượng hiện tại, trong khi tự đề cập đến lớp hiện tại.

Nó là cần thiết để tham khảo một phần tử lớp bằng cách sử dụng self, và tham chiếu đến một phần tử đối tượng bằng cách sử dụng $ this.

self::STAT // refer to a constant value
self::$stat // static variable
$this->stat // refer to an object variable  

19
2018-05-08 06:58





Đây là một ví dụ về việc sử dụng chính xác $ this và self cho non-static   và biến thành viên tĩnh:

<?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();
?> 

17
2017-12-06 11:26





Theo http://www.php.net/manual/en/language.oop5.static.php không có $self. Chỉ có $this, để đề cập đến thể hiện hiện tại của lớp (đối tượng) và self, có thể được sử dụng để chỉ các thành viên tĩnh của một lớp. Sự khác biệt giữa một thể hiện đối tượng và một lớp được đưa vào chơi ở đây.


16
2017-09-30 06:29



Gợi ý: Đọc câu trả lời này khi vấp vào axit. - a20