Thứ Tư, 2 tháng 10, 2013

Tối ưu hóa PHP



Tối ưu hóa code php,hướng dẫn tối ưu hóa code php nếu với số lượng lớn người sử dụng cùng lúc,mã nguồn được viết hợp lí, có thể cải thiện các chương trình của bạn được tăng một cách đá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:

...
$my_array[$i] = strtr($my_array[$i], '0', '1');
...

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 (http://www.xdebug.org). 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 (http://php.net/manual/en/book.apc.php)
- eAccelerator (http://eaccelerator.net/)
- XCache (http://xcache.lighttpd.net/)

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ể.

Lập trình Web bằng PHP là gì?



Nên bắt đầu từ đâu?
PHP không khó, lập trình web không khó, cái khó là không biết phải học những kiến thức bổ trợ nào, học tới đâu, học bao nhiêu cho đủ? Chữ đủ ở đây được hiểu là đủ dùng, không thiếu và cũng đừng “thừa”.
Để trả lời câu hỏi đó, chúng ta sẽ lấy việc “Lập trình web bằng PHP” làm trung tâm, các kiến thức bổ trợ khác như CSS, HTML, JS, SQL, v.v… sẽ được đề cập khi cần thiết.
Lập trình là gì?
Lập trình web là gì?
Lập trình web bằng PHP là gì?

Như ở một comment trong phần bài tập, tôi có nói, diễn giải theo một cách dễ hình nhung nhất thì lập trình tức là bạn đang cố gắng diễn đạt một mong muốn nào đó của bạn theo cách mà máy tính hiểu được, thông qua một ngôn ngữ trung gian.
Bạn có thể lập trình để làm nhiều việc, phục vụ cho nhiều mục đích khác nhau. Lập trình web được hiểu là lập trình phục vụ thường trực cho các công việc liên quan đến web. Nhưng không có nghĩa rằng các “ngôn ngữ lập trình web” (như PHP, ASP, JSP…) chỉ làm được những gì liên quan đến web. Vì một “ngôn ngữ lập trình web” trước hết phải là một ngôn ngữ lập trình.

Tôi lấy ví dụ, các bạn có thể dùng Pascal/C++ để lập trình tính toán cộng trừ nhân chia, giai thừa, tính lim, log, cộng trừ mảng, tạo ma trận, quản lý sinh viên, xử lý dữ liệu dạng tệp / dạng văn bản… Thế thì bạn cũng có thể dùng PHP để làm toàn bộ những việc đó (dù rằng mỗi ngôn ngữ sẽ có điểm mạnh yếu riêng, và trong một giới hạn nào đó, một vài điểm rất nhỏ ở ngôn ngữ này có thể không / khó thực hiện được ở ngôn ngữ kia).



Trong ít nhất là 2 bài tới, bạn phải thay đổi ngay suy nghĩ rằng “PHP là ngôn ngữ lập trình web nên để học PHP nhất thiết phải có webserver, hosting; nhất thiết phải có trình duyệt, nhất thiết phải rành, hoặc phải biết chút ít về HTML…”
Không. PHP là PHP, nó là một ngôn ngữ lập trình, và chúng ta sẽ học những bài đầu tiên của ngôn ngữ lập trình này mà không cần quan tâm tới bất cứ kiến thức bổ trợ nào như HTML, CSS, JavaScript hay MySQL. Chúng ta cũng không cần trình duyệt hay máy chủ. Tất cả những gì cần có là một phần mềm soạn thảo văn bản (notepad cũng đủ xài) và trình thông dịch lệnh PHP.

Nếu đã từng học qua / đọc qua các tài liệu giáo khoa liên quan đến lập trình, các bạn sẽ biết khái niệm về trình thông dịch và trình biên dịch. Tôi đề nghị các bạn xoá bỏ 2 khái niệm này và đồng nhất chúng thành “diễn dịch” cho dễ hiểu và dễ trình bày. Tôi sẽ cố gắng che lấp đi tất cả những gì có thể làm các bạn khó hiểu hay nản chí, và việc này đôi khi đòi hỏi một số định nghĩa “không đúng đắn” lắm, nhưng tôi cam kết sẽ quay lại nói lại cho rõ, cho đúng vào một thời điểm thích hợp, khi mà điều đó thực sự cần thiết cho các bạn. Vậy nên, từ bây giờ chúng ta sẽ gọi chung PHP là trình thông dịch.

Trình thông dịch, trước hết là một phần mềm. Tức là một file cụ thể trên đĩa cứng trong máy tính, có đuôi là .EXE. Để có trình thông dịch PHP, các bạn phải đi “đao lột” ở đâu đó về một file PHP.EXE (tất nhiên, đôi khi file PHP.EXE này đòi hỏi phải có nhiều file khác đi kèm thì mới hoạt động đúng đắn được). Sau khi có file PHP.EXE này rồi, bạn chỉ cần “chạy” nó, sử dụng nó, nhập dữ liệu cho nó, truyền tham số cho nó… thế là đủ để học lập trình PHP… phe phé!



Ví dụ, bạn có thư mục PHP ở ổ đĩa C, và trong C:\PHP có file PHP.EXE, thì bạn chỉ cần khởi động dòng lệnh MSDOS (bằng cách vào Window / Run, gõ lệnh CMD và nhấn Enter). Sau đó, tại con nháy C:\>, hãy gõ lệnh C:\>PHP\PHP.EXE để chạy phần mềm PHP.

Phần mềm PHP này cho phép bạn khởi chạy kèm theo một vài tham số. Và tham số đơn giản nhất là đường dẫn tới file mã nguồn PHP. Ví dụ, khi bạn gõ “C:\>PHP\PHP.EXE C:\PHP\MaNguon\Bai1.php” thì phần mềm PHP.EXE sẽ được thực thi, nó tìm tới file Bai1.PHP (tại thư mục MaNguon, trong thư mục PHP ở ổ đĩa C) để đọc nội dung, thực hiện các câu lệnh trong file Bai1.PHP và trả về kết quả.

Tất nhiên, ở đây chúng ta đang gọi thực thi PHP.EXE từ dòng lệnh – cửa sổ MS DOS nên kết quả trả về cũng sẽ là những dữ liệu hiển thị trong cửa sổ MS DOS. Không có trình duyệt, không có HTML hay CSS gì ở đây hết! Các bạn xem thêm hình minh hoạ ở dưới đây.