Hướng dẫn dùng get peak trong PHP

Vietnamese (Tiếng Việt) translation by Giang Nam (you can also view the original English article)

Hai lần một tháng, chúng tôi xem xét lại một số các độc giả yêu thích các bài viết từ trong suốt lịch sử của Nettuts +.

Ngay cả sau khi sử dụng PHP trong nhiều năm qua, chúng tôi vấp ngã khi chức năng và các tính năng mà chúng tôi không biết gì về. Một số người trong số này có thể khá hữu ích, nhưng underused. Với ý nghĩ đó, tôi đã biên soạn một danh sách chín PHP chức năng vô cùng hữu ích và tính năng mà bạn nên quen thuộc với.


1. chức năng với số tùy ý của lập luận

Bạn đã biết rằng PHP cho phép bạn xác định các chức năng với đối số tùy chọn. Nhưng đó cũng là một phương pháp cho phép số hoàn toàn tùy ý của chức năng đối số.

Đầu tiên, đây là một ví dụ với các tùy chọn chỉ cần lập luận:

// function with 2 optional arguments
function foo($arg1 = '', $arg2 = '') {

  echo "arg1: $arg1\n";
	echo "arg2: $arg2\n";

}


foo('hello','world');
/* prints:
arg1: hello
arg2: world
*/

foo();
/* prints:
arg1:
arg2:
*/

Bây giờ, chúng ta hãy xem làm thế nào chúng ta có thể xây dựng một chức năng chấp nhận bất kỳ số nào của các đối số. Thời gian này chúng tôi sẽ sử dụng func_get_args():

// yes, the argument list can be empty
function foo() {

	// returns an array of all passed arguments
	$args = func_get_args();

	foreach ($args as $k => $v) {
		echo "arg".($k+1).": $v\n";
	}

}

foo();
/* prints nothing */

foo('hello');
/* prints
arg1: hello
*/

foo('hello', 'world', 'again');
/* prints
arg1: hello
arg2: world
arg3: again
*/

2. sử dụng Glob() để tìm tập tin

Nhiều chức năng PHP có tên dài và mô tả. Tuy nhiên, nó có thể được khó để biết những gì một chức năng đặt tên glob() hiện trừ khi bạn đã quen thuộc với thuật ngữ đó từ những nơi khác.

Hãy suy nghĩ của nó như một phiên bản có khả năng của các chức năng scandir(). Nó có thể cho phép bạn tìm kiếm các tập tin bằng cách sử dụng mẫu.

// get all php files
$files = glob('*.php');

print_r($files);
/* output looks like:
Array
(
    [0] => phptest.php
    [1] => pi.php
    [2] => post_output.php
    [3] => test.php
)
*/

Bạn có thể lấy nhiều loại tập tin như thế này:

// get all php files AND txt files
$files = glob('*.{php,txt}', GLOB_BRACE);

print_r($files);
/* output looks like:
Array
(
    [0] => phptest.php
    [1] => pi.php
    [2] => post_output.php
    [3] => test.php
    [4] => log.txt
    [5] => test.txt
)
*/

Lưu ý rằng các tập tin có thể thực sự được quay trở lại với một con đường, tùy thuộc vào truy vấn của bạn:

$files = glob('../images/a*.jpg');

print_r($files);
/* output looks like:
Array
(
    [0] => ../images/apple.jpg
    [1] => ../images/art.jpg
)
*/

Nếu bạn muốn nhận được đường dẫn đầy đủ để mỗi tập tin, bạn có thể chỉ cần gọi hàm realpath() trên các giá trị trả về:

$files = glob('../images/a*.jpg');

// applies the function to each array element
$files = array_map('realpath',$files);

print_r($files);
/* output looks like:
Array
(
    [0] => C:\wamp\www\images\apple.jpg
    [1] => C:\wamp\www\images\art.jpg
)
*/

3. bộ nhớ cách sử dụng thông tin

Bằng cách quan sát sử dụng bộ nhớ của các kịch bản của bạn, bạn có thể tối ưu hóa mã của bạn tốt hơn.

PHP có một bộ thu rác và một người quản lý bộ nhớ khá phức tạp. Số lượng bộ nhớ được sử dụng bởi script của bạn. có thể đi lên và xuống trong thời gian thực hiện một kịch bản. Để sử dụng bộ nhớ hiện tại, chúng tôi có thể sử dụng chức năng memory_get_usage(), và để có được số tiền cao nhất của bộ nhớ được sử dụng tại bất kỳ điểm nào, chúng tôi có thể sử dụng chức năng memory_get_peak_usage().

echo "Initial: ".memory_get_usage()." bytes \n";
/* prints
Initial: 361400 bytes
*/

// let's use up some memory
for ($i = 0; $i < 100000; $i++) {
	$array []= md5($i);
}

// let's remove half of the array
for ($i = 0; $i < 100000; $i++) {
	unset($array[$i]);
}

echo "Final: ".memory_get_usage()." bytes \n";
/* prints
Final: 885912 bytes
*/

echo "Peak: ".memory_get_peak_usage()." bytes \n";
/* prints
Peak: 13687072 bytes
*/

4. CPU sử dụng thông tin

Đối với điều này, chúng tôi sẽ sử dụng chức năng getrusage(). Hãy nhớ rằng điều này là không có sẵn trên nền tảng Windows.

print_r(getrusage());
/* prints
Array
(
    [ru_oublock] => 0
    [ru_inblock] => 0
    [ru_msgsnd] => 2
    [ru_msgrcv] => 3
    [ru_maxrss] => 12692
    [ru_ixrss] => 764
    [ru_idrss] => 3864
    [ru_minflt] => 94
    [ru_majflt] => 0
    [ru_nsignals] => 1
    [ru_nvcsw] => 67
    [ru_nivcsw] => 4
    [ru_nswap] => 0
    [ru_utime.tv_usec] => 0
    [ru_utime.tv_sec] => 0
    [ru_stime.tv_usec] => 6269
    [ru_stime.tv_sec] => 0
)

*/

Đó có thể nhìn một chút khó hiểu trừ khi bạn đã có một nền tảng quản trị hệ thống. Đây là lời giải thích của mỗi giá trị (bạn không cần phải ghi nhớ này):

  • ru_oublock: ngăn chặn các hoạt động đầu ra
  • ru_inblock: ngăn chặn đầu vào hoạt động
  • ru_msgsnd: thư gửi
  • ru_msgrcv: tin nhắn nhận được
  • ru_maxrss: thiết lập cư trú tối đa kích thước
  • ru_ixrss: phân chia sẻ kích thước bộ nhớ
  • ru_idrss: tích phân unshared kích thước dữ liệu
  • ru_minflt: trang đòi
  • ru_majflt: trang lỗi
  • ru_nsignals: tín hiệu nhận được
  • ru_nvcsw: thiết bị chuyển mạch bối cảnh tự nguyện
  • ru_nivcsw: thiết bị chuyển mạch không tự nguyện bối cảnh
  • ru_nswap: giao dịch hoán đổi
  • ru_utime.tv_usec: thời gian người dùng sử dụng (miligiây)
  • ru_utime.tv_sec: thời gian người dùng sử dụng (giây)
  • ru_stime.tv_usec: Hệ thống thời gian sử dụng (miligiây)
  • ru_stime.tv_sec: Hệ thống thời gian sử dụng (giây)

Để xem bao nhiêu sức mạnh CPU kịch bản đã tiêu thụ, chúng ta cần phải nhìn vào 'sử dụng thời gian' và 'thời gian hệ thống' giá trị. Giây và phần miligiây được cung cấp một cách riêng biệt theo mặc định. Bạn có thể chia các giá trị miligiây 1 triệu, và thêm vào giá trị giây để có được những giây tất cả như một số thập phân.

Hãy xem một ví dụ:

// sleep for 3 seconds (non-busy)
sleep(3);

$data = getrusage();
echo "User time: ".
	($data['ru_utime.tv_sec'] +
	$data['ru_utime.tv_usec'] / 1000000);
echo "System time: ".
	($data['ru_stime.tv_sec'] +
	$data['ru_stime.tv_usec'] / 1000000);

/* prints
User time: 0.011552
System time: 0
*/

Mặc dù kịch bản mất khoảng 3 giây để chạy, sử dụng CPU là rất rất thấp. Bởi vì trong quá trình hoạt động ngủ, kịch bản thực sự không tiêu thụ tài nguyên CPU. Có rất nhiều nhiệm vụ khác, mà có thể mất thời gian thực, nhưng không thể sử dụng thời gian CPU, như chờ đợi cho đĩa hoạt động. Như vậy như bạn thấy, sử dụng CPU và chiều dài thực tế của thời gian là không luôn luôn giống nhau.

Dưới đây là một ví dụ khác:

// loop 10 million times (busy)
for($i=0;$i<10000000;$i++) {

}

$data = getrusage();
echo "User time: ".
	($data['ru_utime.tv_sec'] +
	$data['ru_utime.tv_usec'] / 1000000);
echo "System time: ".
	($data['ru_stime.tv_sec'] +
	$data['ru_stime.tv_usec'] / 1000000);

/* prints
User time: 1.424592
System time: 0.004204
*/

Mà mất khoảng 1,4 giây của thời gian CPU, hầu như tất cả đều là thời gian người dùng, vì đã có không có cuộc gọi hệ thống.

Thời gian hệ thống là lượng thời gian CPU thực hiện các cuộc gọi hệ thống dành cho hạt nhân trên danh nghĩa của chương trình. Dưới đây là một ví dụ về điều đó:

$start = microtime(true);
// keep calling microtime for about 3 seconds
while(microtime(true) - $start < 3) {

}

$data = getrusage();
echo "User time: ".
	($data['ru_utime.tv_sec'] +
	$data['ru_utime.tv_usec'] / 1000000);
echo "System time: ".
	($data['ru_stime.tv_sec'] +
	$data['ru_stime.tv_usec'] / 1000000);

/* prints
User time: 1.088171
System time: 1.675315
*/

Bây giờ chúng ta có khá nhiều hệ thống thời gian sử dụng. Điều này là bởi vì các tập lệnh gọi hàm microtime() nhiều lần, mà thực hiện một yêu cầu thông qua hệ điều hành để lấy các thời gian.

Cũng bạn có thể nhận thấy những con số khá không thêm lên đến 3 giây. Điều này là bởi vì có lẽ đã quá trình khác trên máy chủ là tốt, và kịch bản không sử dụng 100% CPU cho suốt thời gian 3 giây.


5. kỳ diệu hằng

PHP cung cấp hữu ích diệu hằng lấy hiện tại số dòng (__LINE__), đường dẫn tệp (__FILE__), đường dẫn thư mục (__DIR__), tên chức năng (__FUNCTION__), tên lớp (__CLASS__), phương pháp tên (__METHOD__) và không gian tên (__NAMESPACE__).

Chúng tôi sẽ không bao gồm mỗi một trong những trong bài viết này, nhưng tôi sẽ chỉ cho bạn một vài trường hợp sử dụng.

Bao gồm các kịch bản khác, đó là một ý tưởng tốt để sử dụng các __FILE__ hằng số (hay cũng __DIR__ thời PHP 5.3):

// this is relative to the loaded script's path
// it may cause problems when running scripts from different directories
require_once('config/database.php');

// this is always relative to this file's path
// no matter where it was included from
require_once(dirname(__FILE__) . '/config/database.php');

Sử dụng __LINE__ làm cho gỡ lỗi dễ dàng hơn. Bạn có thể theo dõi xuống số dòng:

// some code
// ...
my_debug("some debug message", __LINE__);
/* prints
Line 4: some debug message
*/

// some more code
// ...
my_debug("another debug message", __LINE__);
/* prints
Line 11: another debug message
*/

function my_debug($msg, $line) {
	echo "Line $line: $msg\n";
}

6. tạo duy nhất ID

Có thể có những tình huống mà bạn cần để tạo ra một chuỗi duy nhất. Tôi đã thấy nhiều người sử dụng chức năng md5() cho điều này, mặc dù nó có nghĩa là không chính xác cho mục đích này:

// generate unique string
echo md5(time() . mt_rand(1,1000000));

Đó là thực sự là một chức năng PHP tên là uniqid() có nghĩa là để được sử dụng cho việc này.

// generate unique string
echo uniqid();
/* prints
4bd67c947233e
*/

// generate another unique string
echo uniqid();
/* prints
4bd67c9472340
*/

Bạn có thể nhận thấy rằng ngay cả khi các dây duy nhất, họ có vẻ tương tự như đối với một số ký tự đầu tiên. Điều này là bởi vì các chuỗi được tạo ra có liên quan đến máy chủ thời gian. Điều này thực sự có một tác dụng phụ tốt đẹp, như đi kèm mỗi id mới được tạo ra sau đó trong thứ tự chữ cái, do đó, họ có thể được sắp xếp.

Để giảm cơ hội nhận được một bản sao, bạn có thể vượt qua một tiền tố hoặc các tham số thứ hai để tăng dữ liệu ngẫu nhiên:

// with prefix
echo uniqid('foo_');
/* prints
foo_4bd67d6cd8b8f
*/

// with more entropy
echo uniqid('',true);
/* prints
4bd67d6cd8b926.12135106
*/

// both
echo uniqid('bar_',true);
/* prints
bar_4bd67da367b650.43684647
*/

Chức năng này sẽ tạo ra chuỗi ngắn hơn so với md5(), mà sẽ còn giúp bạn tiết kiệm một số không gian.


7. đăng trên

Bạn đã bao giờ cần thiết để lưu trữ một biến phức tạp trong cơ sở dữ liệu hoặc một tập tin văn bản? Bạn không phải đi lên với một giải pháp ưa thích để chuyển đổi các mảng hoặc đối tượng của bạn thành định dạng chuỗi, như PHP đã có chức năng cho mục đích này.

Hiện có hai phương pháp phổ biến của serializing biến. Dưới đây là một ví dụ có sử dụng các serialize() và unserialize():

// a complex array
$myvar = array(
	'hello',
	42,
	array(1,'two'),
	'apple'
);

// convert to a string
$string = serialize($myvar);

echo $string;
/* prints
a:4:{i:0;s:5:"hello";i:1;i:42;i:2;a:2:{i:0;i:1;i:1;s:3:"two";}i:3;s:5:"apple";}
*/

// you can reproduce the original variable
$newvar = unserialize($string);

print_r($newvar);
/* prints
Array
(
    [0] => hello
    [1] => 42
    [2] => Array
        (
            [0] => 1
            [1] => two
        )

    [3] => apple
)
*/

Đây là phương pháp nguồn gốc đăng trên PHP. Tuy nhiên, kể từ khi JSON đã trở nên phổ biến trong những năm qua, họ đã quyết định để thêm hỗ trợ cho nó trong PHP 5,2. Bây giờ bạn có thể sử dụng các chức năng cũng như json_encode() và json_decode():

// a complex array
$myvar = array(
	'hello',
	42,
	array(1,'two'),
	'apple'
);

// convert to a string
$string = json_encode($myvar);

echo $string;
/* prints
["hello",42,[1,"two"],"apple"]
*/

// you can reproduce the original variable
$newvar = json_decode($string);

print_r($newvar);
/* prints
Array
(
    [0] => hello
    [1] => 42
    [2] => Array
        (
            [0] => 1
            [1] => two
        )

    [3] => apple
)
*/

Nó là nhỏ gọn hơn, và tốt nhất của tất cả, tương thích với javascript và nhiều ngôn ngữ khác. Tuy nhiên, các đối tượng phức tạp, một số thông tin có thể bị mất.


8. nén Strings

Khi nói về nén, chúng tôi thường nghĩ về tập tin, chẳng hạn như kho lưu trữ ZIP. Nó có thể nén các dây dài trong PHP, mà không liên quan đến bất kỳ tập tin lưu trữ.

Trong ví dụ sau, chúng tôi sẽ sử dụng gzcompress() và gzuncompress () chức năng:

$string =
"Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Nunc ut elit id mi ultricies
adipiscing. Nulla facilisi. Praesent pulvinar,
sapien vel feugiat vestibulum, nulla dui pretium orci,
non ultricies elit lacus quis ante. Lorem ipsum dolor
sit amet, consectetur adipiscing elit. Aliquam
pretium ullamcorper urna quis iaculis. Etiam ac massa
sed turpis tempor luctus. Curabitur sed nibh eu elit
mollis congue. Praesent ipsum diam, consectetur vitae
ornare a, aliquam a nunc. In id magna pellentesque
tellus posuere adipiscing. Sed non mi metus, at lacinia
augue. Sed magna nisi, ornare in mollis in, mollis
sed nunc. Etiam at justo in leo congue mollis.
Nullam in neque eget metus hendrerit scelerisque
eu non enim. Ut malesuada lacus eu nulla bibendum
id euismod urna sodales. ";

$compressed = gzcompress($string);

echo "Original size: ". strlen($string)."\n";
/* prints
Original size: 800
*/



echo "Compressed size: ". strlen($compressed)."\n";
/* prints
Compressed size: 418
*/

// getting it back
$original = gzuncompress($compressed);

Chúng tôi đã có thể đạt được giảm kích thước gần 50%. Còn các chức năng gzencode() và gzdecode() đạt được kết quả tương tự, bằng cách sử dụng một thuật toán nén khác nhau.


9. đăng ký chức năng Shutdown

Đó là một chức năng được gọi là register_shutdown_function(), mà sẽ cho phép bạn thực hiện một số mã ngay trước khi kết thúc các tập lệnh đang chạy.

Hãy tưởng tượng rằng bạn muốn chụp một số thống kê điểm chuẩn vào cuối thực hiện kịch bản của bạn, chẳng hạn như mất bao lâu để chạy:

// capture the start time
$start_time = microtime(true);

// do some stuff
// ...

// display how long the script took
echo "execution took: ".
		(microtime(true) - $start_time).
		" seconds.";

Lúc đầu, điều này có thể có vẻ tầm thường. Bạn chỉ cần thêm mã dưới cùng rất của các kịch bản và nó chạy trước khi nó kết thúc. Tuy nhiên, nếu bạn đã bao giờ gọi các chức năng exit(), mã sẽ không bao giờ chạy. Ngoài ra, nếu có một lỗi nghiêm trọng, hoặc nếu các kịch bản được chấm dứt bởi người dùng (bằng cách nhấn nút dừng trong trình duyệt), một lần nữa nó có thể không chạy.

Khi bạn sử dụng register_shutdown_function(), mã của bạn sẽ thực hiện không có vấn đề tại sao các kịch bản đã ngừng chạy:

$start_time = microtime(true);

register_shutdown_function('my_shutdown');

// do some stuff
// ...


function my_shutdown() {
	global $start_time;

	echo "execution took: ".
			(microtime(true) - $start_time).
			" seconds.";
}

Kết luận

Bạn có biết của bất kỳ tính năng PHP nào khác mà không được biết đến rộng rãi, nhưng có thể khá hữu ích không? Xin vui lòng chia sẻ với chúng tôi trong các ý kiến. Và cảm ơn bạn đọc!