1. Hàm gọi lại trong PHP là gì?

Hàm gọi lại (calllback) là khái niệm mà một hàm truyền vào một hàm khác như một tham số để nó có thể được thực hiện trước hoặc sau một sự kiện hoặc một sự thay đổi trạng thái nào đó. Ta cứ coi như việc sử dụng hàm gọi lại là như một việc truyền một tham số cho hàm khác.

Sử dụng các thuật ngữ “gọi lại” và “có thể gọi được” có thể hoán đổi cho nhau, tuy nhiên, “gọi lại” theo truyền thống đề cập đến một giá trị chuỗi hoặc mảng hoạt động như một con trỏ hàm , tham chiếu một phương thức hàm hoặc lớp để gọi trong tương lai.

Bất kỳ hàm hiện có nào cũng có thể được sử dụng như một hàm gọi lại. Hàm gọi lại thì có thể là một hàm thông thường trong PHP, cũng có thể là một hàm trong một hướng đối tượng hay cũng có thể là một static method trong một lớp.

Ví dụ: mình sẽ có một ví dụ đơn giản về hàm gọi lại.

<?php
function sayHello($callback) {
echo "Xin chào!</br>";
    // Các câu chuyện khác ở giữa xin chào và tạm biệt
    // ...
    $callback();
}
function sayGoodbye() {
    echo "Tạm biệt!";
}
sayHello('sayGoodbye');
// Kết quả
// Xin chào!
// ...
// Tạm biệt

Hàm sayGoodbye được truyền vào hàm sayHello như một tham số. Cách thực hiện này rất hữu ích khi chúng ta muốn định nghĩa một hàm (sayGoodbye) được thực hiện khi một sự kiện xảy ra (sau các câu chuyện khác). Ví dụ trên đây khá dễ hiểu nhưng có một khía cạnh chưa được bàn đến là việc sử dụng kết quả của hàm gọi trong hàm được gọi. Ví dụ tiếp theo cho thấy hỗ trợ viên sau khi lấy thông tin về lỗi người dùng và sử dụng thông tin này để gọi lại cho khách hàng:

<?php
function sayHello($first_name, $last_name, $callback) {
    $full_name = $first_name . ' ' . $last_name;
    $callback($full_name);
}
function formatName($full_name) {
    echo '<h2 style="color:red;">Xin chào '. $full_name . '!<h2>';
}
sayHello('Nguyễn Văn', 'A', 'formatName');

2. Sử dụng hàm gọi lại trong PHP ở đâu?

Ta sẽ sử dụng hàm gọi lại trong một số trường hợp sau:

  • Khi ứng dụng cần thực hiện một hàm khác dựa trên ngữ cảnh hoặc trạng thái. Hay nói cách khác là muốn thực hiện một việc gì đó khi một sự kiện xảy ra.
  • Sử dụng với hàm ẩn danh(anonymous function) hoặc với Closure
  • Lập trình đa luồng(multiple thread).

Ví dụ: lập trình xử lý đa luồng chúng ta cần một file và ghi vào file một cái gì đó. Vì file này rất lớn nên cần một chút thời gian để mở file. Nếu làm theo cách cũ:

fileObject = open(file)
// Cần phải chờ file được mở thì mới ghi vào file được, có thể mất 5 phút chẳng hạn.
fileObject.write("We are writing to the file.")
// Tiếp theo mới làm được những việc khác
doSomething();

Sử dụng callback chúng ta có thể thực hiện được những việc khác luôn.

fileObject = open(file, writeToFile)
// Không cần phải chờ file mở và ghi vào file, chúng ta có thể thực hiện việc khác luôn.
doSomething();

Ví dụ 2:

function sayHello($first_name, $last_name, $callback) 
{
 $full_name = $first_name . ' ' . $last_name; $callback($full_name);
}
function formatName($full_name) 
{ 
echo "<h2>Xin chào $full_name <h2>";
} 
sayHello('Dau', 'Xanh', 'formatName');
  • Trong ví dụ trên thì khi gọi đến hàm callback thì đồng thời mình cũng truyền cho hàm callback giá trị** $full_name** vào trong hàm callback
  • Bản chất của $callback(full_name) là gọi đến một hàm được xây dựng sẵn trong PHP đó là call_user_func, như vậy callback(full_name) tương đương với call_user_func(callback,full_name). Sử dụng callback có thể có lỗi xảy ra nếu chúng ta callback đến một hàm chưa được định nghĩa, vì vậy chúng ta cần kiểm tra xem có tồn tài callback hay không trước khi sử dụng

3. Gọi lại trong các chức năng do người dùng xác định

Các hàm và phương thức do người dùng định nghĩa cũng có thể lấy các hàm gọi lại làm đối số. Để sử dụng các hàm gọi lại bên trong một hàm hoặc phương thức do người dùng xác định, hãy gọi hàm hoặc phương thức đó bằng cách thêm dấu ngoặc đơn vào biến và truyền các đối số như với các hàm bình thường.

Ví dụ:

<?php
function exclaim($str) {
  return $str . "! ";
}
function ask($str) {
  return $str . "? ";
}
function printFormatted($str, $format) {
 //Gọi hàm gọi lại $ format
  echo $format($str);
}
// Chuyển "exclaim" và "ask" dưới dạng các hàm gọi lại cho printFormatted ()
printFormatted("Hello world", "exclaim");
printFormatted("Hello world", "ask");
?>

4. Array_map() và Array_filter() trong hàm gọi lại

Array_map() chấp nhận tham số truyền vào là một callback function và tham số thứ 2 là một mảng, cho phép callback function mà bạn truyền vào xử lý gì đó với mảng.

Ví dụ:

//array
$names = ['Thành', 'Nam', 'Sơn'];
print_r(array_map(function ($name) {
    return "Xin chao " . ucfirst($name);
}, names));

//output
[0 => 'Xin chao Thành', 1 => 'Xin chao Nam', 2 => 'Xin chao Sơn'];

Tương tự như trên, array_filter() cũng chấp nhận tham số truyền vào là một mảng và một callback, và bạn có thể lọc mảng theo một điều kiện nào đó mà bạn định nghĩa trong callback, thay vì phải dùng foreachif.

Ví dụ:

$input = [1, 2, 3, 4, 5, 6];
$output = array_filter($input, function ($item) {
    return ($item % 2) == 0;
});
print_r($output);
//output
[2, 4, 6]

5. Hàm ẩn danh – Anonymous Function

Như tiltle thì đây chính là nguồn gốc của callback, hay nói một cách ngắn gọn thì callback chính là một hàm ẩn danh. Đúng như cái tên thì đây chính là một function vô danh, tức là nó sẽ không có tên mà chỉ được định nghĩa là một function và sẽ thực hiện một công việc gì đó.

Ví dụ: đây sẽ là một function bình thường, có nghĩa là nó được khai báo một cách bình thường và sử dụng một cách bình thường.

//định nghĩa
function functionName() {
  // 
}
// gọi
functionName();

Về cơ bản thì mọi thứ của hàm ẩn danh đều là một function bình thường. Sự khác nhau căn bản mà ta dễ thấy nhất chính là tên của Anonymous Function là không có và thứ hai là kết thúc nó luôn là một dấu chấm phẩy phía sau dấu ngoặc cuối cùng.

Ví dụ:

function($yourName, $myName) {
    return "Hi $yourname, My name is $myName";
};

Ta cũng có thể gán cho Anonymous Function một biến bất kỳ. Biến này sau đó được gọi ra tương tự một function hay thậm chí là có thể cho vào một mảng và sẽ cho ta một số hữu ích trong nhiều trường hợp.

Ví dụ:

$goodMorning = function ($name) {
    return "Good morning, $name";
};
// gọi
echo $goodMorning('Thành Nguyễn');
//output
//Good morning, Thành Nguyễn

Hay ta tạo hẳn một mảng các function:

$ai = [
    function () {
        echo "Chào buổi sáng!"
    },  
    function () {
        echo "Các bạn cần gì ở lập trình từ đầu?"
    },
    ...
]
// Gọi
$ai[1]();
//Output
Các bạn cần gì ở lập trình từ đầu?