12/08/2018, 13:03

Những tính năng mới và những cập nhật mới trong PHP 7

Giới thiệu chung PHP 7 được phát hành chính thức vào ngày 03 tháng 12 năm 2015. Nó mang đến cho lập trình viên, những nhà phát triển những trải nghiệm rất thú vị. Thật vậy, php 7 vừa công bố những tính năng mới, vừa thay đổi, cải thiện một số chức năng để tăng hiệu năng, giúp cho việc quản lý tài ...

Giới thiệu chung

PHP 7 được phát hành chính thức vào ngày 03 tháng 12 năm 2015. Nó mang đến cho lập trình viên, những nhà phát triển những trải nghiệm rất thú vị. Thật vậy, php 7 vừa công bố những tính năng mới, vừa thay đổi, cải thiện một số chức năng để tăng hiệu năng, giúp cho việc quản lý tài nguyên một cách hiệu quả nhất. Như chúng ta đã biết, phiên bản PHP chạy ổn định nhất hiện nay là PHP 5.6, tuy nhiên bản release mới đây nhất lại mang tên PHP 7. Tại sao lại như vậy? Tại sao không phải là PHP 6? Trên thực tế các nhà phát hành cũng đã có nhiều cuộc tranh luận về vấn đề này. Xuất phát từ chính lý do trong quá khứ cũng đã tồn tại phiên bản mang tên PHP 6, tuy nhiên nó ra đời không đáp ứng đúng như kì vọng của các nhà phát hành cũng như các nhà phát triển. Phiên bản PHP 6 tồn tại nhiều bug, nên nó chỉ tồn tại với danh phiên bản thử nghiệm. Và để tránh việc người dùng bị lẫn lộn với phiên bản thử nghiệm PHP 6 thì các nhà phát hành lấy tên PHP 7 làm phiên bản chính thức cho version lần này.

Đột phá lớn nhất của PHP 7 chính là hiệu suất đáng kinh ngạc mà nó tăng lên cho các ứng dụng. Đây là hiệu quả của việc đưa vào sử dụng engine Zend, một engine có cấu trúc dữ liệu nhỏ gọn, phân chia dữ liệu và giải phóng bộ nhớ một cách hợp lý nhất. Do đó, các ứng dụng sử dụng PHP 7 thì hiệu suất tăng gấp đôi, mức tiêu thụ bộ nhớ giảm đi một nửa. Những biểu đồ sau cho thấy hiệu suất, mức sử dụng tài nguyên của PHP 7 vượt trội thế nào so với các phiên bản trước PHP 5.6 và HHVM 3.7 php7_magento1.9.pngphp7_drupal8.pngphp7_wordpress.png Chúng ta có thể thấy được rằng so với phiên bản chạy ổn định gần nhất PHP 5.6 thì với hầu hết các ứng dụng như Magento 1.9, Drupal 7, 8, wordpress 2.6, 4.1, thì PHP 7 đều vượt trội về tốc độ xử lý số request trong 1 đơn vị thời gian. Ngoài ra nếu so sánh với các ngôn ngữ khác về tốc độ render một context thì PHP 7 vượt trội hơn hẳn so với ruby2.1, python 2.7.8, perl 5.18.4: php7_ruby_python_perl.png

Các toán tử mới Spaceship và Null Coalescing

Toán tử Spaceship được gọi với cái tên chính thức là Combined Comparison Operator(toán tử so sánh kết hợp). Toán tử này được kí hiệu như sau: <=>. Toán tử spaceship này trả về giá trị 0 nếu cả hai toán hạng bằng nhau, trả về giá trị 1 nếu toán hạng bên trái lớn hơn, và -1 nếu toán hạng bên phải lớn hơn. Nó cũng được gọi là một toán tử so sánh three-way, và đã tồn tại trong những ngôn ngữ lập trình phổ biến khác như Perl và Ruby. Tổng quát hóa toán tử này như sau:

php7_combined_comparison_operator.png

Toán tử Null Coalescing được thể hiện bằng hai dấu chấm hỏi (??). Bạn có thể sử dụng nó khi muốn kiểm tra xem liệu một cái gì đó đã tồn tại và trả về một giá trị mặc định hay không. Toán tử coalesce trả về kết quả của toán hạng đầu tiên nếu nó tồn tại và không null, và trả về toán hạng thứ hai trong các trường hợp khác. Ví dụ sau đây là cách mà toán tử này giảm được thời gian với những khai báo cơ bản:

// Fetches the request có tham số user and trả về kết quả 'nobody' nếu user đó không tồn tại
$username = $_GET['user'] ?? 'nobody';
// đoạn code tương đương với:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// Lấy một object có id là $id và nếu không get được thì gán bằng giá trị mặc định $default_model
$model = Model::get($id) ?? $default_model;
// đoạn code tương đương với:
if (($model = Model::get($id)) === NULL) { $model = $default_model; }

// Parse JSON ảnh metadata, và nếu có lỗi thì gán giá trị awidth bằng 100
$imageData = json_decode(file_get_contents('php://input'));
$awidth = $imageData['awidth'] ?? 100;
// đoạn code tương đương với:
$awidth = isset($imageData['awidth']) ? $imageData['awidth'] : 100;

Khai báo chính xác kiểu dữ liệu

Khai báo kiểu vô hướng hướng đến hai kiểu khai báo là coercive (default) and strict. PHP 7 cho phép các lập trình viên nâng cao chất lượng code của họ bằng cách tự định nghĩa kiểu dữ liệu trả về. Khi mà không hiểu hết được những hàm có sẵn thì PHP hỗ trợ tính năng khai báo kiểu trả về của một function. PHP 7 giới thiệu 4 kiểu khai báo mới cho các kiểu vô hướng int, float, string, bool. Những kiểu vô hướng này cho phép lập trình viên trả về các giá trị họ đang mong đợi là int, float, string, bool. Ngoài ra PHP 7 còn hỗ trợ thêm cho phép lập trình viên trả về giá trị kiểu tham số. Ví dụ:

// Coercive mode
function sumOfInts(int ...$ints)
{
    return array_sum($ints);
}

var_dump(sumOfInts(2, '3', 4.1)); // int(9)

Để có thể sử dụng kiểu strict, bắt buộc lập trình viên phải khai báo declare() trên đầu file. Điều này có nghĩa là khai báo này chỉ có tác dụng cấu hình trên file đó. Khai báo này không những ảnh hưởng đến các loại tham số mà còn cả những kiểu trả về của chức năng. Nó có ý nghĩa tương đương với đệ quy. Khi khai báo kiểu dữ liệu này nếu có bất kì type-check mà xảy ra lỗi thì Exception sẽ bắn ra tương ứng:

declare(strict_types=1);

function multiply(float $x, float $y)
{
    return $x * $y;
}

function add(int $x, int $y)
{
    return $x + $y;
}

var_dump(multiply(2, 3.5)); // float(7)
var_dump(add('2', 3)); // Fatal error: Uncaught TypeError: Argument 1 passed to add() must be of the type integer, string given...

Chú ý rằng lệnh được thực thi khi check-type hoàn thành. Điều này có nghĩa là kiểu strict chỉ áp dụng cho các function/medthod được gọi. Ví dụ về kiểu đệ quy như sau:

function arraysSum(array ...$arrays): array
{
    return array_map(function(array $array): int {
        return array_sum($array);
    }, $arrays);
}

print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));
/* Output
Array
(
    [0] => 6
    [1] => 15
    [2] => 24
)
*/

Bổ sung thêm các class ẩn danh

PHP 7 cho phép bạn sử dụng các class ẩn danh (anonymous), đây là một đặc trưng đã có trong những ngôn ngữ lập trình hướng đối tượng khác như C# và Java. Một class anonymous là một class không có tên. Đối tượng mà nó khởi tạo có cùng chức năng như một đối tượng của một lớp có tên.

Một class ẩn danh có thể được sử dụng với một tên class:

  • Khi class đó không được dùng để ghi dữ liệu
  • Khi class đó chỉ được dùng 1 lần trong suốt quá trình thực thi

Một class ẩn danh là một class mà không có tên với các chức năng không có gì khác biệt so với các class có tên, chúng được sử dụng cú pháp của class nhưng khuyết tên như sau:

<?php
/* implementing an anonymous console object from your framework maybe */
(new class extends ConsoleProgram {
    public function main() {
       /* ... */
    }
})->bootstrap();

/* return an anonymous implementation of a Page for your MVC framework */
return new class($controller) implements Page {
    public function __construct($controller) {
        /* ... */
    }
    /* ... */
};

/* vs */
class MyPage implements Page {
    public function __construct($controller) {
        /* ... */
    }
    /* ... */
}
return new MyPage($controller);

/* return an anonymous extension of the DirectoryIterator class */
return new class($path) extends DirectoryIterator {
   /* ... */
};

/* vs */
class MyDirectoryIterator {
    /* .. */
}
return new MyDirectoryIterator($path);

/* return an anon class from within another class (introduces the first kind of nested class in PHP) */
class MyObject extends MyStuff {
    public function getInterface() {
        return new class implements MyInterface {
            /* ... */
        };
    }
}

/* return a private object implementing an interface */
class MyObject extends MyStuff {
    /* suitable ctor */

    private function getInterface() {
        return new class(/* suitable ctor args */) extends MyObject implements MyInterface {
            /* ... */
        };
    }
}

Closure call() Method (Bao đóng phương thức call())

Phương thức call() cho closures được dùng như là một cách viết tắt khi gọi một closure khi lấy phạm vị đối tượng tham chiếu tới nó. Điều này làm cho code nhỏ gọn hơn, loại bỏ sự tạo ra yếu tố trung gian trước khi gọi nó.

class A {private $x = 1;}

// Pre PHP 7 code
$getXCB = function() {return $this->x;};
$getX = $getXCB->bindTo(new A, 'A'); // intermediate closure
echo $getX(); // 1

// PHP 7+ code
$getX = function() {return $this->x;};
echo $getX->call(new A); // 1

Lọc unserialize()

Tính năng này nhằm cung cấp những bảo mật tốt hơn khi unserialize() đối tượng trên dữ liệu không đáng tin. Nó ngăn chặn code injection bằng cách cho các nhà phát triển để các lớp rỗng có thể unserialize() được.

// converts all objects into __PHP_Incomplete_Class object
$data = unserialize($foo, ["allowed_classes" => false]);

// converts all objects into __PHP_Incomplete_Class object except those of MyClass and MyClass2
$data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]);

// default behaviour (same as omitting the second argument) that accepts all classes
$data = unserialize($foo, ["allowed_classes" => true]);

Quản lý lỗi và ngoại lệ dễ dàng hơn

Phải công nhận rằng, việc kiểm soát và có khả năng bắt các fatal error chưa bao giờ là công việc dễ dàng đối với hầu hết các lập trình viên PHP. Engine Exceptions mới sẽ cho phép các lập trình viên thay thế những loại lỗi này với các ngoại lệ (exception). Nếu ngoại lệ không bắt được thì PHP sẽ tiếp tục trả về các fatal error giống như các phiên bản PHP 5.X hiện hành.

Các đối tượng EngineException mới không mở rộng Exception Base Class. Điều này đảm bảo khả năng tương thích ngược và các kết quả từ hai kiểu exception khác nhau trong việc quản lý lỗi: truyền thống và engine exceptions.

Để cho phép các lập trình viên có thể bắt được cả hai, PHP 7 giới thiệu một Parent Class mới dưới cái tên là BaseException.

try {
    call_method(null); // oops!
} catch (EngineException $e) {
    echo "Exception: {$e->getMessage()}
";
}

// Exception: Call to a member function method() on a non-object

Dùng use khai báo namespace

PHP 7 cho phép nhóm nhiều các namespace của các class cha đồng vị. Điều này có nghĩa là tránh được sự rườm rà khi cần khai báo quá nhiều các class cha đồng vị bằng nhiều dòng.

// Pre PHP 7 code
use somenamespaceClassA;
use somenamespaceClassB;
use somenamespaceClassC as C;

use function somenamespacefn_a;
use function somenamespacefn_b;
use function somenamespacefn_c;

use const somenamespaceConstA;
use const somenamespaceConstB;
use const somenamespaceConstC;

// PHP 7+ code
use somenamespace{ClassA, ClassB, ClassC as C};
use function somenamespace{fn_a, fn_b, fn_c};
use const somenamespace{ConstA, ConstB, ConstC};

Loại bỏ các chức năng không còn được hỗ trợ

Mục tiêu của PHP 7 là nhằm giải phóng không gian bộ nhớ để tăng tốc độ hệ thống, vì vậy việc loại bỏ các chức năng cũ, không còn nhiều giá trị sử dụng là điều cần thiết.

Tất cả các mục bị gỡ bỏ đã không được tán thành một thời gian trong PHP 5, vì vậy không nhiều lập trình viên đã không sử dụng chúng trong một thời gian dài. Tuy nhiên nếu một ứng dụng đang chạy kế thừa từ các phiên bản PHP cũ hơn thì bản PHP 7 này có thể sinh ra lỗi trên ứng dụng mà bạn đang chạy với phiên bản cũ.

Các phần mở rộng đã được gỡ ra:

  • ext/ereg (kể từ PHP 5.3; dùng ext/pcre instead)
  • ext/mysql (kể từ PHP 5.5; dùng ext/mysqli hoặc ext/pdo_mysql)

Các chức năng sau được loại bỏ:

  • dl trong fpm-fcgi (kể từ PHP 5.3)
  • set_magic_quotes_runtime và magic_quotes_runtime (kể từ PHP 5.4)
  • set_socket_blocking (kể từ PHP 5.4; dùng stream_set_blocking thay thế)
  • mcrypt_generic_end (kể từ PHP 5.4; dùng mcrypt_generic_deinit thay thế)
  • mcrypt_ecb, mcrypt_cbc, mcrypt_cfb và mcrypt_ofb (kể từ PHP 5.5, dùng mcrypt_encrypt và mcrypt_decrypt thay thế)
  • datefmt_set_timezone_id và IntlDateFormatter::setTimeZoneID (kể từ PHP 5.5; dùng datefmt_set_timezone hoặc IntlDateFormatter::setTimeZone thay thế)

Các tùy chọn ini được loại bỏ:

  • xsl.security_prefs (kể từ PHP 5.4; dùng XsltProcessor::setSecurityPrefs thay thế)
  • iconv.input_encoding, iconv.output_encoding, iconv.internal_encoding, mbstring.http_input, mbstring.http_output và mbstring.internal_encoding (kể từ PHP 5.6; dùng php.input_encoding, php.internal_encoding và php.output_encoding thay thế)

Ngoài ra còn một số chức năng khác:

  • biến $is_dst tham số của hàm mktime() và gmmktime() functions (kể từ PHP 5.1)
  • # kiểu comments trong ini files (kể từ PHP 5.3; dùng ; kiểu comments thay thế)
  • Tên loại chuỗi trong setlocale() (kể từ PHP 5.3; dùng LC_* hằng số thay thế)
  • uploads file dùng curl không an toàn (kể từ PHP 5.5; dùng CurlFile thay thế)
  • preg_replace() (kể từ PHP 5.5; dùng preg_replace_callback thay thế)
  • PDO::PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT driver option (kể từ PHP 5.6; dùng PDO::ATTR_EMULATE_PREPARES thay thế)
  • CN_match và SNI_server_name (kể từ PHP 5.6; dùng peer_name thay thế)

0