Học lập trình web PHP trực tuyến tốt nhất

2015 là một năm quan trọng đối với PHP. 11 năm kể từ khi ra mắt phiên bản 5.0, một phiên bản lớn cuối cùng cũng sắp ra lò! PHP 7 được dự tính sẽ ra mắt vào cuối năm nay với nhiều tính năng mới và sự cải thiện mạnh mẽ về hiệu năng hoạt động.

Vậy sự kiện này có tác động như thế nào đến những kiến thức về PHP của bạn? Những thay đổi nào đã xảy ra? Liệu có an toàn không nếu nâng cấp lên version 7? Bài viết này sẽ trả lời những câu hỏi đó và mang đến một cái nhìn khái quát về PHP 7 cho bạn.

Cải thiện hiệu năng

Hiệu năng hoạt động chính xác là lý do quan trọng nhất để bạn nâng cấp server ngay khi PHP 7 bản chính thức ra mắt. Phần cốt lõi được tái cấu trúc và giới thiệu bở phpng RFC khiến PHP 7 nhanh chẳng kém gì HHVM, thậm chí còn nhanh hơn. Các bản benchmark chính thức có kết quả rất ấn tượng: hầu hết các ứng dụng thực tế hiện nay chạy trên PHP 5.6 sẽ chạy nhanh ít nhất là gấp đôi khi lên PHP 7.

Để biết thêm chi tiết về các so sánh hiệu năng, bạn có thể xem slide thuyết trình của Rasmus Lerdorf tại PHP Australia. (Bạn có thể ấn phím mũi tên để di chuyển giữa các slide). Dưới đây là một vài kết quả benchmark WordPress trích từ slide:

Học lập trình PHP kiếm tiền

PHP 7 xử lý số lượng request/giây hơn gấp đôi so với PHP 5.6, điều này cho thấy hiệu năng hoạt động tăng 100% đối với các website Wordpress.

Vấn đề tương thích với phiên bản cũ

Hãy nói về một vài điều có thể làm hỏng một ứng dụng PHP đang chạy trên các phiên bản cũ.

Loại bỏ các mục bị phản đối (Deprecated item)

Một loạt các mục bị phản đối đã bị loại bỏ. Các mục này đã bị đưa vào danh sách deprecate từ lâu, hi vọng là trong các bạn không có ai sử dụng tới chúng. Điều này cũng có thể ảnh hưởng tới các ứng dụng có tuổi đời lâu năm.

Đặc biệt, thẻ dạng ASP ( <%, <%=%> ) đã bị loại bỏ cùng với thẻ script ( <script language="php"> ). Hãy chắc rằng bạn đang sử dụng thẻ <?php thay vì những thẻ kia.

Phần mở rộng ereg (và tất cả các hàm ereg_* ) đã bị phản đối từ PHP 5.3. Nó được thay thế bởi phần mở rộng PCRE (các hàm preg_* ) được giới thiệu với rất nhiều tính năng. Phần mở rộng mysql (và các hàm mysql_* ) cũng bị phản đối từ PHP 5.5. Để chuyển đổi trực tiếp, bạn có thể sử dụng phần mở rộng mysqli và các hàm mysqli_* để thay thế.

Cú pháp biến thống nhất

Cú pháp biến thống nhất có ý nghĩa đối với việc giải quyết một chuỗi các mẫu thuẫn khi xử lý các biểu thức biến-biến. Xét ví dụ sau:

<?php
class Person
{
   public $name = 'Erika';
   public $job = 'Developer Advocate';
}

$person = new Person();
$property = [ 'first' => 'name', 'second' => 'info' ];
echo "\nMy name is " . $person->$property['first'] . "\n\n";

Trong PHP 5, biểu thức $person->$property['first'] được xử lý như $person->{$property['first']}. Trong các điều kiện thực tế, nó được biên dịch tương tự $person->name, cho bạn kết quả "My name is Erika". Mặc dù đây là một trường hợp ít gặp nhưng nó cho thấy sự mâu thuẫn rõ ràng với thứ tự thực hiện biểu thức bình thường là từ trái qua phải.

Với PHP 7, biểu thức $person->$property['first'] được xử lý như {$person->$property}['first']. Trình biên dịch sẽ thực hiện $person->$property trước; do đó đoạn code mẫu trên sẽ không hoạt động trên PHP 7 vì $property là một mảng và không thể được chuyển thành chuỗi ký tự.

Một cách nhanh chóng và dễ dàng để sửa lỗi này là khai báo rõ ràng thứ tự thực hiện tính toán bằng các dấu ngoặc nhọn (ví dụ: $person->{$property['first']}), cách này sẽ đảm bảo kết quả khớp nhau giữa PHP 5 và PHP 7.

Nhờ vào cú pháp thống nhất từ trái qua phải, rất nhiều biểu thức trước kia không hợp lệ thì nay lại trở nên hợp lệ. Để minh họa cho cách xử lý mới này, xét ví dụ class sau:

<?php
class Person
{
   public static $company = 'DigitalOcean';
   public function getFriends()
   {
       return [
           'erika' => function () {
               return 'Elephpants and Cats';
           },
           'sammy' => function () {
               return 'Sharks and Penguins';
           }
       ];
   }

   public function getFriendsOf($someone)
   {
       return $this->getFriends()[$someone];
   }

   public static function getNewPerson()
   {
       return new Person();
   }
}

Với PHP 7, chúng ta có thể tạo ra sự kết hợp lồng nhau và các tổ hợp khác nhau giữa các toán tử:

$person = new Person();
echo "\n" . $person->getFriends()['erika']() . "\n\n";
echo "\n" . $person->getFriendsOf('sammy')() . "\n\n";

Đoạn code này sẽ cho ra lỗi cú pháp với PHP 5 nhưng lại hoạt động tốt với PHP 7.

Tương tự, truy nhập tĩnh nhiều cấp cũng có thể thực hiện được ở PHP 7:

echo "\n" . $person::getNewPerson()::$company . "\n\n";

Trong PHP 5, lệnh trên sẽ cho kết quả lỗi cú pháp kinh điển T_PAAMAYIM_NEKUDOTAYIM.

Fatal Error khi khai báo nhiều mệnh đề "default"

Đây cũng là một trường hợp hiếm gặp và liên quan nhiều hơn tới lỗi logic trong phần code của bạn. Khi bạn khai báo nhiều mệnh đề mặc định cho một lệnh switch, PHP 5 sẽ không báo lỗi, mệnh đề mặc định cuối cùng sẽ được sử dụng, dẫn tới việc itmf lỗi khó khăn hơn. Khác với PHP 5, ở PHP 7 bạn sẽ bị báo lỗi Fatal Error: Switch statements may only contain one default clause.

Cơ chế ngoại lệ (Engine Exceptions)

Cơ chế ngoại lệ có ý nghĩa với việc đơn giản hóa xử lý lỗi trong ứng dụng của bạn. Các thông báo lỗi fatal đã có và các lỗi nghiêm trọng được thay thế bởi các ngoại lệ (exception) giúp chúng ta bắt lỗi và có thể xử lý lỗi ấy như hiển thị lỗi ra màn hình, lưu lỗi lại trong hệ thống theo dõi, thực hiện các hàm xử lý lỗi.

Cơ chế ngoại lệ được thực hiện theo cách tương thích với các phiên bản cũ nhưng vẫn sẽ có các trường hợp đặc biệt tác động tới ứng dụng khi các ứng dụng cũ có dùng các hàm xử lý lỗi do người dùng tự viết. Ví dụ:

<?php
set_error_handler(function ($code, $message) {
   echo "ERROR $code: " . $message . "\n\n";
});

function a(ArrayObject $b){
   return $b;
}

a("test");

echo "Hello World";

 Đoạn code này in ra thông báo lỗi khi gặp lỗi sai kiểu dữ liệu với lời gọi hàm a() mà tham số truyền vào là một chuỗi ký tự. Trong PHP 5, nó sinh lỗi E_RECOVERABLE được bắt bởi hàm tự viết trên, kết quả in ra màn hình sẽ là:

ERROR 4096: Argument 1 passed to a() must be an instance of ArrayObject, string given, called in /data/Projects/php7dev/tests/test04.php on line 12 and defined(...)

Hello World

Lưu ý là code sẽ tiếp tục thực thi vì lỗi đã được xử lý. Trong PHP 7, đoạn code này sẽ sinh ra ngoại lệ TypeError (không phải lỗi!) do đó hàm bắt lỗi sẽ không được gọi. Dưới đây là output mà bạn sẽ nhận được:

Fatal error: Uncaught TypeError: Argument 1 passed to a() must be an instance of ArrayObject, string given, called in /vagrant/tests/test04.php on line 12 and defined in /vagrant/tests/test04.php:7
Stack trace:
#0 /vagrant/tests/test04.php(12): a('test')
#1 {main}
  thrown in /vagrant/tests/test04.php on line 7

Code sẽ dừng thực thi vì ngoại lệ này chưa được xử lý. Để giải quyết vấn đề này, bạn nên bắt lỗi bằng khối lệnh try/catch. Một lưu ý quan trọng là hệ thống ngoại lệ đã thay đổi để hỗ trợ cơ chế ngoại lệ mới với ít ảnh hưởng nhất tới các code cũ:

  • Throwable interface

    • Exception implements Throwable

      • ErrorException extends Exception

      • RuntimeException extends Exception

    • Error implements Throwable

      • TypeError extends Error

      • ParseError extends Error

      • AssertionError extends Error

Về cơ bản, điều này có nghĩa là hệ thống ngoại lệ bắt tất cả (catch-all Exception) hiện tại là Throwable thay vì Exception. Điều này sẽ không ảnh hưởng tới code cũ nhưng các bạn hãy nhớ tới vấn đề này khi xử lý cơ chế ngoại lệ mới trong PHP 7.

Tính năng ngôn ngữ mới

Phần thú vị nhất khi tìm hiểu PHP 7 chính là những tính năng mới sẽ xuất hiện trong phiên bản này. Chúng ta sẽ cùng điểm qua các tính năng đó.

Toán tử mới

PHP 7 mang tới cho chúng t hai toán tử mới: spaceship (toán tử so sánh kết hợp) và null coalesce operator (toán tử ??).

Toán tử spaceship ( <=> ) còn được gọi là toán tử so sánh kết hợp, toán tử này có thể được sử dụng để rút gọn các chuỗi so sánh phức tạp. Xét ví dụ sau:

$a <=> $b

Biểu thức trên cho ra kết quả -1 nếu $a nhỏ hơn $b, 0 nếu $a bằng $b, 1 nếu $a lớn hơn $b. Nó là một dạng rút gọn cho biểu thức sau:

($a < $b) ? -1 : (($a > $b) ? 1 : 0)

Toán tử null coalesce operator ( ?? ) được dùng trong trường hợp rất phổ biến: kiểm tra một biến đã được đặt giá trị trước khi sử dụng hay không, nếu có thì trả về giá trị của biến, không thì trả về một giá trị mặc định nào đó. Trong PHP 5, bạn sẽ làm việc đó tương tự như thế này:

$a = isset($b) ? $b : "default";

Còn với PHP 7, ta có thể đơn giản hóa nó thành:

$a = $b ?? "default";

Scalar Type Hints

Một trong những tính năng gây tranh cãi nhiều nhất của PHP 7 là scalar type hints, với tính năng này ta có thể sử dụng các kiểu vô hướng như integer, float, string, boolean để nhắc kiểu trong hàm và phương thức. Mặc định trong PHP là các kiểu vô hướng không bị hạn chế, có nghĩa là nếu bạn truyền một giá trị float vào tham số integer thì giá trị này sẽ bị ép kiểu thành integer và không báo lỗi.

Giờ chúng ta có thể kích hoạt chế độ giới hạn (strict mode) để báo lỗi khi truyền tham số sai kiểu. Ví dụ:

<?php
function double(int $value)
{
   return 2 * $value;
}
$a = double("5");
var_dump($a);

Đoạn code này sẽ không tạo ra lỗi vì chúng ta chưa dùng strict mode. Điều duy nhất xảy ra ở đây là sự chuyển đổi kiểu, string "5" được truyền vào sẽ bị ép kiểu thành integer trong phạm vi hàm double.

Nếu muốn chỉ có dữ liệu kiểu integer mới được truyền vào hàm double, ta có thể kích hoạt strict mode bằng cách thêm dòng lệnh sau vào dòng đầu tiên của đoạn code: declare(strict_types = 1)

<?php
declare(strict_types = 1);
function double(int $value)
{
   return 2 * $value;
}
$a = double("5");
var_dump($a);

Đoạn code này giờ sẽ sinh ra lỗi Fatal error: Uncaught TypeError: Argument 1 passed to double() must be of the type integer, string given.

Return Type Hints (nhắc kiểu trả về)

Một tính năng quan trọng nữa mà PHP 7 giới thiệu là khả năng định nghĩa kiểu trả về của phương thức và hàm, cách vận hành của nó tương tự scalar type hints.

<?php
function a() : bool
{
   return 1;
}
var_dump(a());

Đoạn code này sẽ chạy không gặp lỗi gì và cho ra kết quả được tự động chuyển kiểu thành bool. Nếu bạn bật strict mode (cách làm như trên với scalar type hints), bạn sẽ nhận được thông báo lỗi:

Fatal error: Uncaught TypeError: Return value of a() must be of the type boolean, integer returned

Thêm một lưu ý, các lỗi này là các ngoại lệ có thể bắt và xử lý thông qua khối lệnh try/catch. Nhắc kiểu trả về có thể sử dụng bất cứ kiểu dữ liệu hợp lệ nào, không chỉ giới hạn ở kiểu vô hướng.

Sắp tới

PHP 7 timeline cho thấy một phiên bản ổn định sẽ ra mắt vào giữa tháng 10. PHP 7 đang trong giai đoạn phát hành các phiên bản gần chính thức, bản beta đã có để các bạn có thể kiểm thử. Các bạn có thể xem bản gần chính thức với tất cả thay đổi sẽ có trong PHP 7 để biết thêm chi tiết.

Dù có thể không có thông báo về tính năng mới nào nhưng vẫn có thể có các thay đổi trước khi phiên bản chính thức được ra mắt, do đó các bạn không nên sử dụng PHP 7 cho dự án thực tế vào thời điểm này. Các bạn có thể thử trải nghiệm PHP 7 thông qua Vagrant VM được tạo bởi Rasmus Lerdorf. Đội ngũ xây dựng PHP 7 khuyến khích mọi người dùng thử ứng dụng với PHP 7 và thông báo bất kỳ lỗi nào mà bạn tìm ra.

Chúc các bạn code vui với PHP 7!

Bài viết được dịch từ blog DigitalOcean.