PHP magic methods
Mở đầu Nếu bạn đang đọc đến dòng này, có nghĩa là bạn đang đọc bài viết của mình trên Viblo tại địa chỉ https://viblo.asia/posts Bạn tự hỏi tại sao mình lại mở đầu như vậy, tất nhiên là ko phải vì hâm rồi, mình viết để cho ai đó đọc được bài này trên 1 trang khác biết rằng trang đó đang clone ...
Mở đầu
Nếu bạn đang đọc đến dòng này, có nghĩa là bạn đang đọc bài viết của mình trên Viblo tại địa chỉ https://viblo.asia/posts
Bạn tự hỏi tại sao mình lại mở đầu như vậy, tất nhiên là ko phải vì hâm rồi, mình viết để cho ai đó đọc được bài này trên 1 trang khác biết rằng trang đó đang clone trang Viblo này thôi =))
Giờ là đến phần chính, chúng ta sẽ tìm hiểu về các Magic methods trong PHP.
Nội dung
Giả sử ta có 1 class như thế này:
class Tweet { }
Và tiếp theo chúng ta sẽ xem magic method cụ thể trong class này như thế nào.
Construct && Destruct
Trong php thì magic method __construct() rất là phổ biến mà chúng ta hay thường gặp nhất.
Hàm __construct() được gọi 1 cách tự động khi mà object được khởi tạo lần đầu tiên. Điều này có nghĩa chúng ta có thể inject các thông số và phụ thuộc để thiết lập object.
public function __construct($id, $text) { $this->id = $id; $this->text = $text; } $tweet = new Tweet(123, 'Hello world');
Khi ta tạo ra một instance mới của đối tượng Tweet, các param được truyền vào object thông qua __construct() method. Như chúng ta thấy, không cần phải gọi phương thức vì nó sẽ được tự động gọi.
Khi có 1 object đc extend, thì object này cũng có __construct(), và chúng ta sẽ muốn dùng cả construct của cha lẫn con:
class Entity { protected $meta; public function __construct(array $meta) { $this->meta = $meta; } } class Tweet extends Entity { protected $id; protected $text; public function __construct($id, $text, array $meta) { $this->id = $id; $this->text = $text; parent::__construct($meta); } }
Sau khi tạo đối tượng, đôi khi chúng ta ghét nó mà muốn destroy nó đi, thì method __destruct() được gọi. Giống construct, destruct được gọi tự động, php sẽ care vụ này.
public function __destruct() { $this->connection->destroy(); }
Sau cuộc mây mưa với object, construct làm tung tóe mọi thứ, thì destruct sẽ làm sạch tất cả, ví dụ cắt như kết nối tới đâu đó, bla bla...
Nhưng thực sự mà nói thì chúng ta chả mấy khi cần đến cái method này.
Getting && Setting
Khi làm việc với object, chúng ta luôn cần phải truy cập các thuộc tính của object, đó là điều đương nhiên, chứ object sinh ra để làm gì :v
$tweet = new Tweet(123, 'hello world'); echo $tweet->text; // 'hello world'
Tuy nhiên, nói chung, các thuộc tính của một đối tượng sẽ được thiết lập protected và do đó cố gắng truy cập vào một property theo cách này sẽ gây ra lỗi (gì đó).
Do đó, __get() method đc sử dụng đến:
public function __get($property) { if (property_exists($this, $property)) { return $this->$property; } }
Phương pháp __get() chấp nhận tên của các property mà ta đang tìm kiếm như một tham số. Trong đoạn mã trên, đầu tiên ta kiểm tra xem property có tồn tại trên các đối tượng hiện tại hay không. Nếu có, ta có thể trả lại chúng từ các đối tượng.
Chúng ta không cần phải gọi phương thức __get() vì PHP sẽ tự động gọi chúng khi ta cố gắng truy cập vào một property mà không phải public.
Nếu chúng ta cố gắng thiết lập một property không thể access, __set() method sẽ được kích hoạt. Phương thức này lấy property mà chúng ta đã cố gắng truy cập và các giá trị mà ta đang cố để thiết lập như là hai đối số.
Dúng như này chẳng hạn:
public function __set($property, $value) { if (property_exists($this, $property)) { $this->$property = $value; } } $tweet->text = 'Setting up my twttr'; echo $tweet->text; // 'Setting up my twttr'
Kiểm tra tồn tại không 1 thuộc tính
Chúng ta vấn hay dùng isset() để kiểm tra có key nào trong 1 mảng hay không? isset($a['b']). Còn đối với 1 object mà có 1 thuộc tính không public thì cũng dùng tương tự như thế:
public function __isset($property) { return isset($this->$property); } isset($tweet->text); // true
Unset 1 thuộc tính
Tương tự isset(), unset() khi dùng để unset 1 thuộc tính không public thì sẽ dùng như thế này:
public function __unset($property) { unset($this->$property); }
To String
__toString() method sẽ trả về 1 string từ object:
public function __toString() { return $this->text; } $tweet = new Tweet(1, 'hello world'); echo $tweet; // 'hello world'
Điều này có nghĩa là khi nào mà ta dùng object như 1 string, ví dụ echo $tweet thì method này sẽ được gọi.
Sleep && wakeup
Ví dụ, nếu ta muốn lưu trữ một đối tượng trong cơ sở dữ liệu, đầu tiên ta sẽ serialise nó, lưu nó, và sau đó khi ta muốn có nó một lần nữa ta lại unserialise nó. Đó là cách thường làm với hàm serialize().
Phương pháp __sleep() cho phép ta xác định các thuộc tính của đối tượng cần được serialise.
$tweet = new Tweet(123, 'Hello world', new PDO ('mysql:host=localhost;dbname=twttr', 'root'));
Ví dụ trên ta có 1 object chứa cả 1 connect tới database, khi mà serialise cái object này, chúng ta ko muốn cả cái connect DB đi theo, __sleep() method chỉ đơn giản là trả về 1 mảng các thuộc tính cần để serialise:
public function __sleep() { return array('id', 'text'); }
Khi lấy object trở lại từ DB, chúng ta cần re-establish cả DB connection, lúc này ta cần đến __wakeup() method:
public function __wakeup() { $this->storage->connect(); }
Call
__call() method sẽ được gọi nếu chúng ta muốn có 1 cái gì đó được xử lý và gán lại vào object (mình hiểu là thế