Laravel and PHP Magic Methods
Theo kết quả survey của trang sitepoint.com, Laravel vượt trội hoàn toàn so với các Framework khác của PHP về sự phổ biến. Nên nhớ rằng Laravel là một framework mới, rất mới so với Zend hay Symfony. Vậy điều gì đã làm cho Laravel trở nên nổi bật như vậy? Đã có rất nhiều bài viết của Viblo phân ...
Theo kết quả survey của trang sitepoint.com, Laravel vượt trội hoàn toàn so với các Framework khác của PHP về sự phổ biến. Nên nhớ rằng Laravel là một framework mới, rất mới so với Zend hay Symfony. Vậy điều gì đã làm cho Laravel trở nên nổi bật như vậy?
Đã có rất nhiều bài viết của Viblo phân tích về sự tuyệt vời của Laravel, trong đó phải kể đến loạt bài viết Laravel Beauty của tác giả @thangtd90 . Trong đó, tác giả đã giới thiệu các công cụ của Laravel, best practices khi làm việc với Laravel và đặc biệt là kiến trúc tổng thể của Laravel thông qua Service Container. Trong bài viết này, tôi sẽ không chú trọng quá nhiều vào kiến trúc Laravel, mà tôi muốn giới thiệu cho các bạn đặc trưng của PHP đóng góp vai trò quan trọng trong việc xây dựng 1 framework tuyệt vời như Laravel.
Chúng ta cùng nhau đến với magic method.
Tổng quan về magic methods trong PHP
PHP có tất cả 15 magic methods. Có 2 methods mà tôi nghĩ ai cũng biết và đã từng làm với PHP đó là __construct() và __toString(). Theo như tên gọi của mình, magic methods sẽ không được lập trình viên gọi trực tiếp mà được PHP gọi 1 cách tự động theo một cơ chế "ma thuật" nào đó được quy định sẵn. __construct() được gọi tự động khi bạn khởi tạo 1 object mới, còn __toString() được gọi tự động khi bạn muốn object của mình hoạt động như một string (ví dụ echo $object). Có 2 ưu điểm nổi bật nhất mà tôi thấy ở magic method, 1 là làm code của bạn sáng sủa và ngắn gọn hơn. Đơn giản là thay vì phải gọi echo $object->toString() thì bạn có thể gọi ngắn gọn echo $object và PHP sẽ làm phần việc chuyển đổi string cho bạn. 2 là cung cấp khả năng viết code trong code. Đây là tư tưởng cơ bản mà trong giới Ruby họ gọi là Meta Programming. Với khả năng "viết code trong code", bạn sẽ tạo ra được hàng tá function hoạt động mượt mà trong khi không phải viết hết function trong class, giúp class của bạn gọn gàng hơn và giảm được việc viết đi viết lại các hàm na ná nhau.
Do có đến 15 magic methods nên tôi không thể liệt kê hết ra trong bài viết này, tôi sẽ chỉ nêu ra 4 hàm overloading của PHP. Đó là __get(), __set(), __call() và __callStatic(). 4 hàm này được đặt chung là các hàm overloading bởi chúng hoạt động trên 1 cơ chế chung là "overload - chất thêm". Khi người dùng truy cập đến một thuộc tính hay một phương thức không tồn tại trong class, hay không access được trong phạm vi hiện tại (ví dụ access hàm private), thì các hàm này sẽ được gọi như một sự bổ sung cho class hiện tại của PHP.
Property Overloading
Đầu tiên là 2 hàm overload với thuộc tính __get và __set. Thử xem chúng hoạt động thế nào qua ví dụ sau.
<?php class User { private $name; public function __construct($name) { $this->name = $name; } public function __get($attribute) { if (property_exists($this, $attribute)) { return $this->$attribute; } return null; } public function __set($attribute, $value) { if (property_exists($this, $attribute)) { $this->$attribute = $value; return true; } return false; } } $user = new User('Peter'); echo $user->name . PHP_EOL; // Output: Peter $user->name = 'David'; echo $user->name . PHP_EOL; // Output: David
Khá đơn giản phải không các bạn. Việc gọi $user->name từ ngoài class User đồng nghĩa với việc bạn truy cập đến 1 thuộc tính không nhìn thấy được. Do vậy, hàm __get() được gọi và giá trị biến $name được trả về. Cách làm này đảm bảo tính đóng gói của lập trình hướng đối tượng mà vẫn mềm mại cho việc get giá trị. Cách giải thích thương tự cũng được áp dụng với __set() với câu lệnh $user->name = 'David';
Method Overloading
Khác với _get() và _set() làm việc với thuộc tính, __call() và __callStatic() làm việc với method. Như tên gọi của nó, __call() sẽ được gọi khi truy cập đến 1 hàm không thể thấy được khi gọi thông qua object. __callStatic() sẽ được gọi khi truy cập đến 1 hàm không thể thấy được khi gọi thông qua hàm static. Xem xét ví dụ sau để biết cách hoạt động của các hàm này.
class Person { private $name; public function __construct($name) { $this->name = $name; } public function __call($name, $arguments) { if (strpos($name, 'set') !== false) { $attribute = strtolower(substr($name, 3)); if (property_exists($this, $attribute)) { $this->$attribute = $arguments[0]; } } } public static function __callStatic($name, $arguments) { if ($name == 'sayHello') { return 'Hello, My name is ' . $arguments[0]; } } public function getName() { return $this->name; } } $person = new Person('David'); echo $person->getName() . PHP_EOL; // Output: David $person->setName('Peter'); echo $person->getName() . PHP_EOL; // Output: Peter echo Person::sayHello('Tom') . PHP_EOL; // Output: Hello, My name is Tom
Rất dễ dàng để hiểu những dòng code trên, đây là một cách tiếp cận khác cho getter, setter