Hướng dẫn dùng php this trong PHP

Nếu bạn đang tìm hiểu về lập trình hướng đối tượng [OOP] ngay từ đầu sẽ làm quen với từ khóa this và self. Và bạn có thể thấy thấy cách sử dụng $this trong một số đoạn mã PHP. Vậy chúng có ý nghĩa và cách dùng như thế nào? Hãy tham khảo bài sau.

  • This trong PHP
  • Self trong PHP

$this tham chiếu đến đối tượng hiện tại của lớp. $this là biến giả được tạo ngay khi đối tượng của lớp được tạo và có thể sử dụng sau khi phương thức lớp đó được gọi từ bên trong ngữ cảnh đối tượng.

Nói chung các hàm thành viên bên trong có thể truy cập các thành viên không tĩnh của một lớp [biến hoặc hàm] cho đối tượng hiện tại.

Hãy quan sát ví dụ dùng $this bên dưới:

Đầu tiên mình sẽ khởi tạo một Class là ConNguoi. Bên trong nó sẽ đặt $ten với giới hạn truy cập là private. Và phương thức setName là public. Có nghĩa là truy cập được mọi nơi, kể cả bên ngoài lớp.

Từ khóa this lúc này được sử dụng để gọi biến bất kỳ của Class và được dùng bên trong hàm thành viên. Hàm thành viên ở đây là setName. $this để trỏ đến đối tượng hiện tại .

Hoặc cũng có thể sử dụng $this để gọi một hàm thành viên khác.

Self trong PHP

Một lớp có thể chứa kết hợp của các thành viên tĩnh và không tĩnh . Để truy cập các thành viên tĩnh của lớp, nó sử dụng self cùng với toán tử phân giải phạm vi ::. Toán tử phân giải phạm vi này còn được gọi là Paamayim Nekudotayim [có nghĩa là dấu hai chấm trong tiếng Do Thái] hoặc trong những từ đơn giản hơn, dấu hai chấm kép.

Các hàm và biến static được liên kết với chính lớp đó. Có nghĩa là bất cứ giá trị nào mà biến static giữ, nó sẽ được chia sẻ cho tất cả các đối tượng được tạo khác.

Nói một cách đơn giản, giả sử chúng ta cập nhật biến static bằng cách sử dụng $a và sau đó dùng lại $a, chúng ta cố gắng truy cập vào cùng một biến static thì sẽ nhận được cùng một giá trị và ngược lại.

Self sử dụng để tham chiếu đến các phương thức và thuộc tính tĩnh [static].

Hãy làm một ví dụ sau:

Khi chạy đoạn mã hoàn toàn bình thường. Nhưng lúc này bạn hãy thử xóa static ngay trước $name đi xem sao.

Sự khác nhau Self This
Có thể được sử dụng trong các hàm [function] tĩnh Được Không
Có thể truy cập biến của lớp và các phương thức Self:: PHP> 5.3 cho phép sử dụng $this với các biến tĩnh sử dụng $this::$foo. Nếu dùng $this->foo sẽ vẫn không được xác định.
Cần một đối tượng khởi tạo Không Cần

Kết luận: Như vậy là bài viết này chúng ta đã tìm hiểu về từ khóa this, selft và cách sử dụng trong Class như thế nào rồi. Nếu có bất kỳ phản hồi nào bạn hãy comment bên dưới mình sẽ giải đáp giúp bạn.

Bài viết này được dịch từ nguồn in PHP, what is the difference between self and $this? nên các ví dụ thực tế tôi xin phép được giữ nguyên từ tác giả.

Nội dung chính

  • Giới thiệu
  • Sử dụng self thay cho $this
  • $this và self trong ngữ cảnh static function
  • $this và self khi truy cập những thuộc tính static và các hàm static
  • Tương tác với hàm static
  • Tương tác với các thuộc tích static trong Class
  • Kết luận
  • Tài liệu tham khảo

Giới thiệu

Khi chúng ta làm việc với PHP, cụ thể là các PHP Framework, bạn đã từng đọc vào core của framework đó? Bạn đã từng nghe về từ khóa static? Bạn đã từng sử dụng self để gọi static function, dùng this để gọi non-static function trong phạm vi class?

Bạn đã bao giờ tự đặt câu hỏi dùng self có gọi được non-static function không? dùng this có gọi được static function không? Điểm khác biệt khi dùng selfthis là gì? Tôi sẽ cùng các bạn làm rõ 2 khái niệm này thông qua bài viết hôm nay.

Nhìn chung, bạn có thể hiểu rằng $this dùng để tham chiếu đến đối tượng [object], còn self dùng để truy cập đến chính class. Tuy nhiên, có một vài điểm đặc trưng chi tiết hơn chúng ta sẽ bàn sâu hơn để thật sự hiểu rõ hơn về 2 khái niệm này.

Tôi sẽ đưa cho các bạn một ví dụ để dễ hình dung. Chúng ta có class Animal và một class khác Tiger kế thừa từ Animal. Class Tiger sẽ override phương thức whichClass[] của class cha. Hãy cùng xem qua cài đặt của 2 class này, đầu tiên ta sẽ dùng $this:

class Animal {

    public function whichClass[] {
        echo "I am an Animal!";
    }

    public function sayClassName[] {
        $this->whichClass[];
    }
}

class Tiger extends Animal {

    public function whichClass[] {
        echo "I am a Tiger!";
    }

}

$tigerObj = new Tiger[];
$tigerObj->sayClassName[];

Ta thấy rằng ở phương thức sayClassName[] của class Animal chúng ta sử dụng từ khóa $this để gọi phương thức whichClass[]. Khi ta khởi tạo đối tượng $tigerObj từ class Tiger và gọi phương thức sayClassName[], phương thức whichClass[] của class Tiger sẽ được gọi chứ không phải phương thức whichClass[] của class Animal. Do vậy kết quả ta nhận được sẽ là

I am a Tiger!

Lý do hết sức đơn giản, con trỏ $this luôn luôn tham chiếu đến đối tượng hiện tại [chính là object $tigerObj], và ta sẽ nhận được kết quả bằng việc gọi phương thức whichClass[] của Tiger chứ không phải Animal. Nói một cách khác đây chính là ví dụ rất dễ hiểu về tính Đa hình [Polymorphism] trong PHP.

Sử dụng self thay cho $this

Hãy cùng thử thay đổi phương thức sayClassName[] trong Animal và sử dụng từ khóa self thay cho $this:

class Animal {

    public function whichClass[] {
        echo "I am an Animal!";
    }

    public function sayClassName[] {
        self::whichClass[];
    }

}

class Tiger extends Animal {

    public function whichClass[] {
        echo "I am a Tiger!";
    }

}

$tigerObj = new Tiger[];
$tigerObj->sayClassName[];

Về cơ bản ví dụ vẫn vậy chỉ thay đổi hết sức nhỏ. Ta sẽ thấy điều kỳ diệu xảy ra, kết quả chúng ta nhận được hoàn toàn khác với kết quả bên trên:

I am an Animal!

Điều gì đã xảy ra? Khi sử dụng self, bản thân nó sẽ biết mình phải gọi phương thức của chính Class chứa nó [tức là gọi hàm whichClass[] của Animal]. Như vậy việc sử dụng self thông qua ví dụ trên đã ngăn chặn tính đa hình bằng việc bỏ qua vtable. Nếu bạn muốn tìm hiểu thêm có thể tham khảo về Vtables.

$this và self trong ngữ cảnh static function

Câu hỏi đặt ra: $this có sử dụng được trong static function không?

Hãy cùng tìm câu trả lời thông qua một ví dụ cài đặt sau:

class Animal {

    public static $name;

    public static function nameChange[]
    {
        $this->name = "Programmer Interview";
    }

}

$animalObj = new Animal[];
$animalObj->nameChange[];

Kết quả nhận được:

FATAL ERROR Uncaught Error: Using $this when not in object context

Lỗi này xảy ra vì chúng ta đang sử dụng con trỏ $this trong static function, tuy nhiên static function thực tế có thể được gọi mà không cần thông qua đối tượng được tạo ra từ class:

Animal::nameChange[];

Nếu ta gọi kiểu này thì việc sử dụng con trỏ $this ở đây không hề có ý nghĩa do con trỏ $this tham chiếu đến đối tượng hiện tại mà với cách gọi trên không hề có một đối tượng nào chúng ta cần làm việc cùng. Trong ngữ cảnh này chúng ta sẽ gặp lỗi như trên.

Tiếp tục với việc thay sử dụng $this bằng self:

class Animal {

public static $name;

    public static function nameChange[]
    {
        self::$name = "Programmer Interview";
    }

}
$animalObj = new Animal[];
$animalObj->nameChange[];

Đoạn code trên chạy ngon mà không hề có lỗi. Đây chính là lý do chính mà self được sử dụng - mục đích chính là truy cập vào thành phần tĩnh [static] trong class. Tiếp tục thực hiện một thay đổi nho nhỏ bằng việc không sử dụng static cho $name nữa:

class Animal {

    // $name is no longer a static variable..
    public $name;

    public static function nameChange[]
    {
        self::$name = "Programmer Interview";
    }

}

$animalObj = new Animal[];
$animalObj->nameChange[];

Kết quả nhận được:

Fatal error: Access to undeclared static property: Animal::$name

Lỗi xảy ra do thành phần non-static sẽ không được phép truy cập trong một static function. Có thể hiểu đơn giản là static function có thể được gọi mà không cần đối tượng từ class, những thành phần non-static thì lại cần đối tượng của class. Khái niệm này được base trên ý tưởng từ C++, các bạn muốn tìm hiểu sâu hơn có thể đọc thêm tại Accessing non static members from a static function.

$this và self khi truy cập những thuộc tính static và các hàm static

Tương tác với hàm static

Hãy cùng xem ví dụ cài đặt sau:

class Animal {

    public static function whichClass[] {
        echo "I am an Animal!";
    }

    public function sayClassName[] {
        self::whichClass[];
    }
}

$animalObj = new Animal[];
$animalObj->sayClassName[];

Chúng ta sử dụng self để gọi static function, và đương nhiên không hề có lỗi gì xảy ra. Giờ ta sẽ thay đổi một chút bằng việc sử dụng $this

class Animal {

    public static function whichClass[] {
        echo "I am an Animal!";
    }

    public function sayClassName[] {
        $this->whichClass[];
    }
}

$animalObj = new Animal[];
$animalObj->sayClassName[];

Thử dự đoán xem điều gì sẽ xảy ra, có thể bạn sẽ nghĩ luôn đến việc báo lỗi trong trường hợp này. Tuy nhiên kết quả không phải như vậy, chúng ta vẫn nhận được kết quả: "I am an Animal!". Bởi vậy, chúng ta có thể gọi static function với từ khóa $this không có vấn đề gì cả.

Tương tác với các thuộc tích static trong Class

Sử dụng $this

Như ta đã thấy ở trên, việc sử dụng $this để gọi các thành phần static không gây lỗi, tuy nhiên cách làm này không nên thực hiện. Ta sẽ làm rõ hơn thông qua ví dụ sau:

class Animal {

    public static $name;

    public static function whichClass[] {
        echo "I am an Animal!";
    }

    public function sayClassName[] {
        $this->name = "My name is Animal";
    }
}

$animalObj = new Animal[];
$animalObj->sayClassName[];

Ta khởi tạo một đối tượng $animalObj từ class Animal, sau đó truy cập tới phương thức sayClassName[] trong đó sử dụng con trỏ $this để truy cập tới thuộc tính static name. Code này chạy không hề có lỗi và như vậy có thể kết luận việc truy cập và thay đổi giá trị của thuộc tính static bằng con trỏ $this là hoàn toàn được phép? Để làm rõ hơn vấn đề này ta lại thực hiện ví dụ sau:

class Animal {

    public static $name;

    public function setClassName[] {
        $this->name = "My name is Animal";
    }
}

$animalObj = new Animal[];

$animalObj2 = new Animal[];

$animalObj->setClassName[];

echo $animalObj->name;

echo $animalObj2->name; //what happens here?

Bạn thử đoán xem kết quả chúng ta nhận được sau khi lấy giá trị của $animalObj->name và $animalObj2->name có giống nhau không? Nếu thực sự có thể dùng $this để truy cập và thay đổi giá trị của thuộc tính static thì dự là ta sẽ nhận được kết quả như nhau [yaoming]

Tuy nhiên đời không như là mơ, kết quả của echo $animalObj->name ta sẽ nhận được "My name is Animal" còn kết quả của echo $animalObj2->name sẽ báo lỗi "Undefined property". Để biết điều gì đang xảy ra tôi sẽ var_dump dữ liệu cho các bạn thấy:

var_dump[$animalObj];
class Animal#1 [1] {
public $name =>
string[17] "My name is Animal"
}

var_dump[$animalObj2];
class Animal#2 [0] {
}

Đến đây chắc các bạn cũng hiểu được phần nào câu chuyện chúng ta đang muốn nói đến, việc gán giá trị cho thuộc tính name trong hàm setClassName[] sử dụng con trỏ $this bản chất không phải chúng ta đang làm việc với thuộc tính static name mà PHP sẽ tự động tạo ra một thuộc tính non-static name [nếu chưa có] trong đối tượng $animalObj và gán giá trị cho nó. Chỉ là chúng ta có cảm giác là chúng ta đang thao tác với chính thuộc tính static mà thôi.

Như vậy có thể đưa ra một số kết luận về thuộc tính static trong PHP như sau:

  • Thuộc tính static không thể truy cập được thông qua object [bằng cách sử dụng ->].
  • Không thể dùng $this để thay đổi giá trị thuộc tính static của Class mà bắt buộc phải dùng self.

Sử dụng self

Quay lại ví dụ ngay trên đây và ta chuyển sang dùng self để truy cập và thay đổi giá trị các thuộc tính tĩnh:

class Animal {

    public static $name;

    public static function whichClass[] {
        echo "I am an Animal!";
    }

    public function sayClassName[] {
        self::$name = "My name is Animal";
    }
}

$animalObj = new Animal[];
$animalObj->sayClassName[];

Mọi thứ đã trở về với những điều bình thường, ta sử dụng self để thay đổi giá trị của thuộc tính static $name, điều này hoàn toàn được phép. Và nếu muốn truy cập tới giá trị của $name ngoài phạm vi Class, ta có thể sử dụng lệnh echo Animal::$name, và ta sẽ nhận được kết quả "My name is Animal" [dance].

Kết luận rút ra được ở đây là: trong PHP, để làm việc với các biến hay thuộc tính static, hãy dùng ngữ cảnh static [VD: dùng self hoặc dùng tên Class].

Kết luận

Thông qua các ví dụ cụ thể hết sức thú vị, chúng ta đã hiểu hơn chút về self$this cũng như cách sử dụng chúng. Ta sẽ tổng hợp lại thông qua bảng so sánh sau:

self$this
Tham chiếu đến Class hiện tại Tham chiếu đến đối tượng [Object] hiện tại
Dùng để gọi các hàm static và tham chiếu đến các thuộc tính static Có thể dùng để gọi các hàm static
Có thể dùng trong các hàm static [để truy cập đến các hàm hay thuộc tính static khác của Class] Không nên dùng để gọi các thuộc tính static [vì sẽ không truy cập được mà lại tự tạo ra các thuộc tính non-static của đối tượng], nên dùng self trong trường hợp này.
Khi được sử dụng sẽ ngăn chặn thể hiện của tính đa hình bằng việc bỏ qua vtable Không thể sử dụng được trong các hàm static

Hy vọng bài dịch và có chém gió thêm chút sẽ giúp các bạn hiểu hơn về self$this.

Tài liệu tham khảo

  1. //www.programmerinterview.com/index.php/php-questions/php-self-vs-this/

Chủ Đề