Với một chương trình PHP hoàn chỉnh hoặc với số lượng lớn người sử dụng cùng lúc, nếu mã nguồn được viết hợp lí, chương trình của bạn được tăng tốc đáng kể.
Trong những năm gần đây, PHP đã trở thành một trong những ngôn ngữ phổ dụng nhất trong lập trình ứng dụng web. Ưu điểm của PHP là mã nguồn mở, miễn phí và không yêu cầu cấu hình hệ thống máy chủ cao. Tuy nhiên, PHP có một số điểm yếu, một trong số đó là tốc độ. Dù vậy, nếu mã nguồn được viết hợp lí, sử dụng PHP bạn hoàn toàn có thể tạo được ứng dụng chạy với tốc độ vượt trội.
Các thủ thuật tăng tốc
Để có thể giải thích rõ ràng, chúng ta bắt đầu bằng một ví dụ:
require_once 'my_functions.php'; function format_str($str) { $str = str_replace('0', '1', $str); return $str; } $my_array = array(); // Mã nguồn để đưa dữ liệu vào $my_array ở đây for ($i = 0; $i < count($my_array); $i++) { if (ereg('^[0-9]+$', $my_array[$i]) && (strlen($my_array[$i]) > 1)) { $my_array[$i] = format_str($my_array[$i]); print $my_array[$i].”<br />”; } }
Vấn đề đầu tiên là việc sử dụng require_once làm chương trình chậm đi, khi đó PHP sẽ phải kiểm tra xem file đã được nạp trước đó chưa. Tất nhiên, trong nhiều trường hợp, điều này là không tránh khỏi. Nhưng nếu không thực sự cần thiết, bạn nên sử dụng require hoặc include thay vì require_once/include_once.
... require 'my_functions.php' ...
Với đoạn mã trên, ở mỗi vòng lặp, PHP sẽ phải chạy count($my_array) và so sánh kết quả với $i. Tuy nhiên, vì dữ liệu của $my_array là không đổi, chạy count với mỗi lần lặp là không cần thiết. Vòng lặp trên có thể được viết lại nhanh hơn như sau:
... $c = count($my_array); for ($i = 0; $i < $c; $i++) { ... Hoặc gọn hơn, có thể viết: ... for ($i = 0, $c = count($my_array); $i < $c; $i++) { ...
Như vậy, count($my_array) sẽ chỉ phải chạy một lần duy nhất, ngay cả khi mảng có vài nghìn phần tử.
Một vấn đề nữa với đoạn mã trên là việc sử dụng print, trong trường hợp này bạn nên sử dụng echo vì echo nhanh hơn khoảng 20% so với print. Lí do đơn giản là vì print làm nhiều việc hơn echo. Một là print thêm vào cuối chuỗi tham số một dấu xuống dòng (\n), hai là nó cũng trả về kết quả (luôn là 1). Khi dùng echo, bạn còn có thể đưa cả 2 chuỗi vào làm tham số, như vậy PHP sẽ không phải làm thao tác nối 2 chuỗi lại với nhau và chỉ đưa từng chuỗi ra màn hình một.
Đoạn mã trên còn sử dụng dấu nháy kép bao quanh <br />. Nếu sử dụng nháy đơn, PHP sẽ không phải tìm biến PHP cũng như các giá trị đặc biệt khác trong chuỗi (ví dụ như \n, \r, \t) và vì vậy mặc nhiên sẽ nhanh hơn.
Dòng mã in dữ liệu ra màn hình vì vậy có thể viết thành:
... echo $my_array[$i], '<br />'; ...
Ngoài ra, đoạn mã trên sử dụng ereg để kiểm tra xem chuỗi chỉ bao gồm một hoặc nhiều chữ số. Bạn không nên dùng ereg mặc dù ereg có vẻ dễ sử dụng hơn với nhiều người. Thay vào đó nên sử dụng preg_match, lí do là vì preg_match có tác dụng y hệt kèm theo ưu điểm vượt trội về tốc độ. Kể từ PHP 5.3.0, ereg không còn được khuyến khích sử dụng, dùng ereg sẽ gây ra khuyến cáo E_DEPRECATED. Dòng trên có thể viết lại thành:
...
if (preg_match('!^[0-9]+$!', $my_array[$i]) && (strlen($my_array[$i]) > 1)) { ...
Thay vì sử dụng strlen như ở trên, bạn cũng có thể sử dụng isset($my_array[$i]{1}). isset là một cấu trúc ngôn ngữ, không phải là hàm như strlen vì vậy sử dụng isset sẽ nhanh hơn strlen. Tất nhiên bạn hoàn toàn có thể thêm kiểm tra độ dài vào ngay trong preg_match – tuy nhiên, đây chỉ là một ví dụ để giúp bạn đọc hiểu được vấn đề.
...
if (preg_match('!^[0-9]+$!', $my_array[$i]) && isset($my_array[$i]{1})) { ...
Đoạn mã trên cũng sử dụng str_replace để thay thế toàn bộ 0 thành 1 trong chuỗi. Nếu mục đích chỉ đơn giản có vậy, bạn nên sử dụng strtr thay vì str_replace vì strtr có thể thực thi nhanh hơn 4 lần. Tương tự, str_replace cũng nhanh hơn preg_replace và preg_replace cũng nhanh hơn ereg_replace rất nhiều. Tùy vào hoàn cảnh, đôi lúc bạn không thể đơn thuần sử dụng strtr mà phải sử dụng str_replace hay thậm chí preg_replace, nhưng dù trong trường hợp nào bạn cũng không nên sử dụng ereg_replace vì mọi việc đều có thể làm được với preg_replace.
...
$str = strtr($str, '0', '1'); ...
Tham số $str cho hàm format_str hoàn toàn có thể là tham chiếu (reference), sử dụng tham chiếu trong trường hợp này sẽ nhanh hơn vì PHP sẽ không phải copy tham số để đưa vào hàm.
...
function format_str(&$str) { $str = strtr($str, '0', '1'); } ...
Tuy vậy, bạn cũng nên cẩn thận khi dùng cách này vì nếu như trong trường hợp bạn vô ý đổi giá trị tham số bên trong hàm, bạn hoàn toàn có thể gây ra một lỗi rất khó tìm.
Hàm format_str rất đơn giản, bạn hoàn toàn có thể loại bỏ hàm này và viết trực tiếp luôn vào trong vòng lặp giúp PHP không phải gọi hàm tự tạo, do vậy tăng tốc được chương trình:
Hết sức cẩn thận khi dùng bởi lẽ cách trên cũng đồng nghĩa với việc bạn đánh đổi cấu trúc chương trình của bạn lấy tốc độ.
Thay vì gửi dữ liệu về máy tính người dùng nhiều lần, bạn cũng có thể tạo bộ đệm (buffer) và chỉ gửi dữ liệu một lần duy nhất. Làm như vậy sẽ giúp giảm thiểu băng thông sử dụng và cũng sẽ làm cho dữ liệu đến được người dùng nhanh hơn. Bạn có thể sử dụng buffer bằng cách thêm ob_start(); vào đầu chương trình.
Chương trình hoàn thiện vì vậy cuối cùng sẽ trở thành:
ob_start();
require 'my_functions.php'; $my_array = array(); // Mã nguồn để đưa dữ liệu vào $my_array ở đây for ($i = 0, $c = count($my_array); $i < $c; $i++) { if (preg_match('!^[0-9]+$!', $my_array[$i]) && isset($my_array[$i]{1})) { $my_array[$i] = strtr($my_array[$i], '0', '1'); echo $my_array[$i], '<br />'; } }
Các phương pháp khác
Để tăng tốc độ của chương trình, nhất thiết phải biết tốc độ thực thi chương trình, quan trọng hơn là phải biết chương trình chậm ở chỗ nào. Làm thế nào để có được thông tin này?
Bạn có thể sử dụng cách đơn giản nhất là tính thời điểm bắt đầu chương trình bằng time(), và thời điểm kết thúc cũng bằng hàm này. Nhưng như vậy bạn chỉ có thể biết được từng file trong chương trình của bạn chạy mất bao lâu mà không thể biết được đến mức hàm hay dòng mã nguồn.
Cách tốt hơn và cũng đơn giản hơn là sử dụng xdebug ( [You must be registered and logged in to see this link.]). Với xdebug bạn có thể biết được đến từng hàm – mỗi hàm được gọi bao nhiêu lần, tốc độ thực thi của mỗi hàm, mỗi file cũng như của toàn bộ chương trình là bao nhiêu, và còn nhiều thông tin bổ ích khác.
Ngoài ra, một cách đơn giản và thường được sử dụng để tăng hiệu năng xử lí của chương trình PHP mà không phải sửa mã nguồn là sử dụng extension tăng tốc cho PHP. Phần lớn các extension này hoạt động bằng cách biên dịch mã nguồn PHP và lưu vào bộ nhớ để có thể được lấy ra sử dụng ngay thay vì phải biên dịch lại mỗi khi chương trình được sử dụng. Một số extension miễn phí phổ dụng:
- Alternative PHP Cache ( [You must be registered and logged in to see this link.]) - eAccelerator ([You must be registered and logged in to see this link.]) - XCache ([You must be registered and logged in to see this link.]) Kết luận
Với một đoạn mã ngắn như ví dụ trong bài viết này bạn khó có thể nhận thấy được khác biệt về tốc độ trừ khi tính tốc độ chạy bằng “xdebug”. Tuy nhiên, với một chương trình PHP hoàn chỉnh hoặc với một số lượng lớn người sử dụng cùng lúc, áp dụng các phương pháp nêu trong bài này có thể giúp chương trình của bạn tăng tốc đáng kể.