PHP V5 và lập trình hướng đối tượng
Khi PHP V5 được phát hành vào năm 2004, nó đã là một bước đại nhảy vọt so với những gì mà PHP V4 cung cấp về mặt thiết kế và lập trình hướng đối tượng OOP (object-oriented program). Nó bổ sung một vài cải tiến cần thiết, thí dụ như khả năng nhìn thấy lớp (class visibility), các bộ dựng (constructors) và các bộ huỷ (destructors) phù hợp, các gợi ý về kiểu, và API phản ảnh lớp (class-reflection API). Nó mở ra cánh cửa cho việc lập trình hướng đối tượng tiên tiến trong PHP, và cho phép bạn thực hiện nhiều mẫu thiết kế dễ hơn nhiều, cùng với các lớp thiết kế và các API tốt hơn.
Trong PHP V5.3, nhiều bổ sung gia tăng đã được đưa vào nhằm tăng cường OOP. Những cải tiến này đã nằm trong lĩnh vực bổ sung cú pháp và cải tiến hiệu năng. Để bắt đầu, chúng ta hãy quan sát các đặc tính mới sẵn có với các phương thức và thành viên tĩnh.
Các phương thức tĩnh được cải thiện và quản lí thành viên (member handling)
Một bổ sung hữu ích trong PHP V5 là khả năng quy định một phương thức hoặc thành viên của một lớp là tĩnh (PHP V4 thực hiện hỗ trợ truy cập tĩnh đến các phương thức và các thành viên của lớp, nhưng không có khả năng quy định rằng phương thức hoặc thành viên đó được thiết kế để truy cập tĩnh). Truy cập tĩnh đặc biệt rất hữu ích để thực hiện mẫu thiết kế đơn lẻ (singleton design), nơi chỉ tồn tại một thực thể của lớp.
PHP V5.3 đã thêm vào một số đặc tính để tăng cường trợ giúp các thành viên và các phương thức tĩnh trong một lớp. Đầu tiên chúng ta sẽ quan sát một phương thức ma thuật vừa được thêm vào: __callStatic().
Phương thức ma thuật _callStatic()
PHP V5 có một số phương thức được xác định một cách đặc biệt, có thể sử dụng bên trong các lớp gọi là các phương thức ma thuật (magic methods). Khi được xác định trong lớp, các phương thức này cung cấp các chức năng đặc biệt, và có khả năng chịu tải (khả năng cho phép một phương thức chấp nhận các kiểu tham số khác nhau) và tính đa dạng (polymorphism) (khả năng cho phép các kiểu dữ liệu khác nhau sử dụng cùng một giao diện). Chúng cũng mở cánh cửa cho việc sử dụng các kiểu khác nhau của các phương thức lập trình OOP và các mẫu thiết kế bằng PHP một cách dễ dàng.
Trong PHP V5.3 có một phương thức ma thuật mới được thêm vào: __callStatic(). Nó làm việc tương tự như phương thức ma thuật __call() được thiết kế để xử lý các cuộc gọi ra phương thức cho các phương thức mà không được xác định hoặc nhìn thấy được trong lớp. Tuy nhiên, __callStatic() được thiết kế để xử lý các cuộc gọi ra phương thức tĩnh, chúng cho chúng ta khả năng thiết kế tốt hơn sự quá tải về phương thức của chúng ta. Một ví dụ về cách sử dụng phương thức này như dưới đây.
Liệt kê 1. Ví dụ về việc sử dụng __callStatic() đối với __call()
{geshibot lang="php" head=""}class Foo
{
public static function __callStatic(
$name,
$args
)
{
echo "Called method $name statically";
}
public function __call(
$name,
$args
)
{
echo "Called method $name";
}
}
Foo::dog(); // outputs "Called method dog statically"
$foo = new Foo;
$foo->dog(); // outputs "Called method dog"
{/geshibot}
Một điều cần lưu ý là PHP thực hiện áp đặt định nghĩa của phương thức __callStatic(); nó phải là chung (public), và nó phải được tuyên bố là tĩnh. Cũng như vậy, phương thức ma thuật __call() cũng phải được xác định là chung, đúng như tất cả các phương thức ma thuật phải là như vậy.
Một đặc tính rất hay của PHP là các biến cho biến (variable variables). Điều có nghĩa là bạn có thể sử dụng chuỗi giá trị của một biến để quy định tên của một biến khác. Nói một cách khác, bạn có thể thực hiện việc gì đó giống như dưới đây.
Liệt kê 2. Các biến “biến” (Variable variables)
{geshibot lang="php" head=""} $x = 'y';
$$x = 'z';
echo $x; // outputs 'y'
echo $y; // outputs 'z'
echo $$x; // outputs 'z'{/geshibot}
Cùng một khái niệm có thể được sử dụng với các hàm, hoặc thậm chí các phương thức lớp như dưới đây.
Liệt kê 3. Tên các hàm biến và phương thức lớp
{geshibot lang="php" head=""}class Dog
{
public function bark()
{
echo "Woof!";
}
}
$class = 'Dog'
$action = 'bark';
$x = new $class(); // instantiates the class 'Dog'
$x->$action(); // outputs "Woof!" {/geshibot}
Điểm mới ở PHP V5.3 là khả năng có tên của lớp khi được quy định là một biến khi thực hiện một cuộc gọi tĩnh. Việc này mở ra một vài khả năng mới, như dưới đây.
{geshibot lang="php" head=""}class Dog
{
public static function bark()
{
echo "Woof!";
}
}
$class = 'Dog';
$action = 'bark';
$class::$action(); //outputs "Woof!" {/geshibot}
Bổ sung này tạo ra khía cạnh về các biến của biến trong PHP đầy đủ, cho phép dùng chúng chỉ trong từng tình huống với PHP.
Chúng ta hãy quan sát một cải tiến hữu ích hơn cho việc sử dụng các phương thức và thành viên tĩnh: liên kết tĩnh muộn (late static binding).
Một trong những điều phiền phức nhất về PHP trước V5.3 là cách phương thức và thành viên tĩnh được xử lý. Cho đến nay, các tham chiếu tĩnh (static references), chẳng hạn như các tham chiếu được làm bản thân nó hoặc __CLASS__, được giải quyết trong phạm vi lớp, trong đó hàm được định nghĩa. Vấn đề là ở chỗ tham chiếu sẽ không đúng nếu lớp được mở rộng và cuộc gọi được thực hiện từ lớp con (child class) mới. Liên kết tĩnh muộn đã được thêm vào PHP V5.3 để giảm bớt vấn đề này. Để minh hoạ rõ hơn, chúng ta hãy tạo ra một lớp với một phương thức tĩnh dưới đây.
Liệt kê 5. Lớp Foo với phương thức tĩnh test()
{geshibot lang="php" head=""}class Foo
{
protected static $name = 'Foo';
public static function test()
{
return self::$name;
}
} {/geshibot}
Chúng ta hãy mở rộng lớp này. Chúng ta sẽ định nghĩa lại thành viên $name trong lớp con này.
Liệt kê 6. Lớp con Bar mở rộng lớp cha Foo
{geshibot lang="php" head=""}class Bar extends Foo
{
protected static $name = 'Bar';
}{/geshibot}
Chúng ta thực hiện cuộc gọi tĩnh trong Liệt kê 7.
Liệt kê 7. Các cuộc gọi phương thức tĩnh test()
{geshibot lang="php" head=""}echo Bar::test(); {/geshibot}
Kết quả từ cuộc gọi đó sẽ là chuỗi Foo. Đây là do tham chiếu self::$name thực hiện trong phương thức test() được thực hiện bằng lớp Foo. Liên kết xuất hiện bằng cách này vì đây là nơi hàm được định nghĩa.
PHP V5.3 đã thêm từ khoá static để cho phép bạn thực hiện một tham chiếu đối với lớp hiện tại. Do đó bạn sẽ thay đổi lớp Foo trên để sử dụng từ khoá này trong Liệt kê 8, và chúng ta sẽ thấy rằng Bar sẽ thay vào kết quả.
Liệt kê 8. Sử dụng từ khoá static
{geshibot lang="php" head=""}class Foo
{
protected static $name = 'Foo';
public static function test()
{
return static::$name;
}
}
class Bar
{
protected static $name = 'Bar';
}
echo Bar::test(); // outputs 'Bar'{/geshibot}
Một điều cần lưu ý về từ khoá static là nó không làm việc như cách làm trong ngữ cảnh không tĩnh. Điều này có nghĩa là các nguyên tắc kế thừa bình thường không áp dụng với các cuộc gọi tĩnh. Từ khoá static sẽ chỉ cần cố gắng giải quyết cuộc gọi trong lớp hiện tại thay cho lớp mà hàm được định nghĩa. Đây là một điều quan trọng cần lưu ý.
Bây giờ chúng ta đã thấy một vài cải tiến với các phương thức và thành viên tĩnh, hãy quan sát một vài lớp mới được bổ sung vào bộ phận rất hữu ích của PHP V5, là Thư viện lớp PHP chuẩn.
Thư viện lớp PHP chuẩn (SPL) là một tập các giao diện và các lớp thêm vào PHP V5, được thiết kế để giải quyết các vấn đề chuẩn. Các vấn đề này gồm việc cho một đối tượng được lặp (iterateable), cho phép một đối tượng đối xử cứ như một mảng, hoặc thực hiện một danh sách móc nối. Lợi điểm của việc sử dụng các lớp và các phương thức này là ở chỗ chúng là riêng cho PHP, nghĩa là chúng sẽ nhanh hơn nếu chúng được thực hiện trong chính PHP. Chúng cũng, trong nhiều ví dụ, cho phép nhiều hàm trong của PHP sử dụng các đối tượng trực tiếp này, chẳng hạn như cách giao diện biến lặp (Iterator interface) cho phép bạn sử dụng cấu trúc foreach để lặp lại trên đối tượng.
PHP V5.3 thêm khá nhiều lớp vào SPL. Có một điều chúng ta đã tham khảo trước đây là cài đặt danh sách móc nối kép (doubly linked list) trong lớp SPL SplDoublyLinkedList. Nó được sử dụng bởi hai lớp SPL mới khác: SplStack, cài đặt stack (vùng nhớ xếp chồng), và SplQueue, cài đặt hàng đợi.
Chúng ta hãy quan sát cách bạn có thể sử dụng lớp SplStack để thực hiện một vùng nhớ.
{geshibot lang="php" head=""}$stack = new SplStack();
// push a few new items on the stack
$stack->push('a');
$stack->push('b');
$stack->push('c');
// see how many items are on the stack
echo count($stack); // returns 3
// iterate over the items in the stack
foreach ( $stack as $item )
echo "[$item],";
// the above outputs: [c],[b],[a]
// pop an item off the stack
echo $stack->pop(); // returns 'c'
// now see how many items are on the stack
echo count($stack); // returns 2{/geshibot}
SqlQueue làm việc theo kiểu tương tự, nhưng nó làm việc như một hàng đợi (vào trước, ra trước; chứ không phải là vào sau, ra trước, như là stack. Ngoài ra, còn cài đặt đống (SplHeap), cũng như là hàng đợi riêng và các cài đặt đống cho vài tình huống nhất định (SplMinHeap, SplMaxHeap và SplPriorityQueue).
Một bổ sung hữu ích nữa là lớp SplFixedArray mà như tên đã ngụ ý, là cài đặt mảng kích thước cố định. Tất nhiên nó khá nhanh — thực ra là nhanh đến mức được đo thử chuẩn, nhanh hơn 10-30% so với cài đặt mảng lắp sẵn trong PHP. Sự tăng tốc này là do việc mảng này có một kích thước cố định, không thay đổi như PHP mặc định, và do không được phép sử dụng các chỉ mục phi số. Liệt kê 10 chỉ ra cách nó được sử dụng.
Liệt kê 10. SplFixedArray
{geshibot lang="php" head=""}$array = new SplFixedArray(3); $array[0] = 'dog'; $array[1] = 'cat'; $array[2] = 'bird'; $a->setSize(4); // increase the size on the fly $array[3] = 'mouse'; foreach ( $array as $value ) echo "[$value],"; Output: [dog],[cat],[bird],[mouse] {/geshibot}
Ngoài ra còn có một vài lớp biến lặp mới đã được thêm vào: FilesystemIterator và GlobIterator. Các biến này làm việc như các lớp biến lặp khác trong PHP, nhưng chúng được thiết kế đặc biệt dùng cho vài cá thể nhất định.
Một thay đổi nữa với SPL là ở chỗ bây giờ nó luôn được kích hoạt trong PHP V5.3. Trong các phiên bản trước của PHP V5, bạn có thể vô hiệu hoá SPL vào lúc dịch, nhưng đối với PHP V5.3, việc này không còn cho phép.
Các bổ sung mới cho SPL thêm một số chức năng hữu ích vào PHP rất dễ sử dụng, cũng như các bổ sung về cấu trúc dữ liệu, thí dụ như các danh sách móc nối kép, stack, heap, và hàng đợi. Các lớp này có thể được sử dụng để thay thế các cài đặt không gian người dùng mà bạn có thể có, chúng sẽ thu được tốc độ gia tăng và sự kết hợp tốt hơn với các cấu trúc và hàm PHP khác nhau.
Giờ chúng ta đã thấy một vài bổ sung mới cho SPL, hãy xem cách OOP trong PHP V5.3 đã thu được một hiệu năng quan trọng và cải thiện việc sử dụng bộ nhớ với bổ sung việc gom rác xoay vòng (circular garbage collection).
Một vấn đề mà các nhà phát triển PHP gặp phải trên quan điểm hiệu năng là việc gom rác (garbage collection). PHP có một bộ gom rác khá đơn giản, mà về cơ bản sẽ thu thập rác cho một đối tượng khi nó không còn nằm trong phạm vi hợp lệ. Cách mà nó thực hiện việc này về mặt nội tại là bằng cách sử dụng một bộ đếm quy chiếu (reference counter), để khi bộ đếm chạm 0 (có nghĩa là không còn các quy chiếu đến đối tượng này nữa), đối tượng sẽ được thu gom và gạch bỏ từ bộ nhớ.
Việc này khá tốt, nhưng có thể trở thành một vấn đề trong các tình thế khi một đối tượng quy chiếu đến một đối tượng khác theo quan hệ cha-con (parent-child relationship). Với tình tình thế này, bộ đếm quy chiếu đối với các đối tượng đó không được thu gom, nên bộ nhớ sử dụng bằng đối tượng này lưu lại trong bộ nhớ không quy chiếu (unreferenced memory) và không được ngừng cấp phát, cho đến khi kết thúc yêu cầu. Chúng ta hãy quan sát một ví dụ khi vấn đề này xảy ra.
Liệt kê 11. Quan hệ lớp cha-con bị thu gom rác không phù hợp trong bản PHP V5.2 và bản trước đó
{geshibot lang="php" head=""}class Parent
{
public function __construct()
{
$this->child = new Child($this);
}
}
class Child
{
public function __construct(
Parent $parent
)
{
$this->parent = $parent;
}
} {/geshibot}
Trong ví dụ này, mỗi khi bạn tạo ra một cá thể của lớp Parent và sau đó cá thể tiếp theo không còn nằm trong phạm vi hợp lệ, bộ nhớ không bao giờ được giải phóng, như vậy kịch bản lệnh sẽ ngày càng lớn thêm trong việc sử dụng bộ nhớ. Có một số giải pháp về không gian người dùng đối với vấn đề này, chẳng hạn như tạo một hàm huỷ cho lớp cha mà sẽ trực tiếp giải phóng đối tượng con. Hàm huỷ này sẽ phải được gọi ra riêng trước khi bỏ thiết đặt quy chiếu lớp cha (parent class reference). Thực hiện tất cả các việc này gây phức tạp một chút cho chương trình của bạn.
Trong PHP V5.3, bộ gom rác sẽ dò tìm các quy chiếu vòng này và có thể giải phóng hết bộ nhớ chúng sử dụng, do đó việc sử dụng bộ nhớ PHP sẽ giữ được ngang bằng khi kịch bản lệnh được thực hiện. Khi mỗi tham chiếu đến lớp Parent được loại bỏ, tham chiếu lớp Child bên trong lớp Parent cũng sẽ được gom rác.
PHP đã tiến thêm một quãng dài về cách hỗ trợ lập trình hướng đối tượng, từ việc hỗ trợ yếu trong những ngày còn PHP V4 cho đến các bổ sung nhiều cải tiến hơn trong PHP V5 và các thay đổi nhỏ với các bản tiếp sau đó. Hiện nay, PHP V5.3 đã đạt được một vài cải thiện hứng thú, gồm các cải tiến về cú pháp như các phương thức ma thuật mới __callStatic(), các cuộc gọi tĩnh động, liên kết tĩnh muộn, phương thức tĩnh, và trợ giúp thành viên. Các bổ sung mới vào SPL với các bổ sung danh sách móc nối kép, các stack, heap, và hàng chờ, đặt ra một vài cấu trúc dữ liệu thông thường trên đầu ngón tay bạn (dễ tìm thấy) và làm cho chúng dễ sử dụng. Cuối cùng, bộ gom rác xoay vòng mong đợi từ lâu đã ổn định bộ nhớ và các vấn đề về hiệu năng làm việc với các lớp tự quy chiếu, bằng cách cài đặt một bộ gom rác nhiều cải tiến mà đã giải phóng bộ nhớ đúng cách cho các cá thể vòng tròn này. Tất cả các đặc tính này làm cho PHP V5.3 trở thành một ngôn ngữ mạnh hơn nhiều đối với lập trình hướng đối tượng.
Các tin khác cùng chuyên mục
- Kỹ thuật lập trình HTML/CSS mới nhất 2020 - 04
- Funny web2.0
- Giải thử vài câu đề thi tốt nghiệp ptth môn toán
- MỘT NGÀY PHẢI KHÁC MỌI NGÀY
- Level 1 - Lập trình hướng đối tượng (P2)
- Level 1 - Lập trình hướng đối tượng (P1)
- PHP 5.3, Phần 3: Không gian tên
- PHP 5.3, Phần 2: Bao đóng và các hàm lambda
- Tăng tốc độ xử lý CSDL MySQL
- Giới thiệu JSON