Callback()??? Thứ mà các bạn vẫn nghe ra rả (hoặc đọc) trong các tutorial về Javascript thì giờ đây còn xuất hiện trong cả PHP. À thật ra thì nó có từ thời nhà Tống rồi nên nếu ai biết rồi thì gạch đá em nhẹ tay
Với các bạn còn chưa tiếp cận PHP lâu chắc sẽ còn xa lạ với khái niệm này hay thậm chí không tin là nó có tồn tại, cho đến khi bạn làm việc với Laravel một thời gian bạn cũng còn chưa nhận ra là mình đã từng sử dụng nó?! Vậy hãy nhìn vào function sau:
1 2 3 4 | <span class="token keyword">return</span> Categories<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">whereHas</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'subtitles'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$query</span><span class="token punctuation">)</span> <span class="token keyword">use</span> <span class="token punctuation">(</span><span class="token variable">$var</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$query</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">where</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'creator'</span><span class="token punctuation">,</span> <span class="token single-quoted-string string">'someone'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Trông quen không?? Thì cái cục function ($query) ...
kia được gọi là một callback function
của whereHas()
Để hiểu được rốt cuộc callback()
trong PHP có gì hay ho thì hãy bắt đầu tìm hiểu về
Anonymous Function
Như title, đây chính là nguồn gốc của callback hay nói ngắn gọn: một callback function chính là một Anonymouse Function.
Đúng như cái tên, đây là một function vô danh, tức là nó 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ì đó.
Đây là một function không vô danh, tức là một function được khai báo bình thường
1 2 3 4 5 6 7 8 | <span class="token comment">//định nghĩa</span> <span class="token keyword">function</span> <span class="token function">functionName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// </span> <span class="token punctuation">}</span> <span class="token comment">// gọi</span> <span class="token function">functionName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Và cách sử dụng cũng bình thường luôn
Anonymouse Function về cơ bản cũng là một function bình thường, nó cũng có thể nhận một tham số và trả về một kết quả nào đó, chỉ khác là chúng được định nghĩa mà không có tên, ví dụ:
1 2 3 4 | <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token variable">$yourName</span><span class="token punctuation">,</span> <span class="token variable">$myName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token double-quoted-string string">"Hi <span class="token interpolation"><span class="token variable">$yourname</span></span>, My name is <span class="token interpolation"><span class="token variable">$myName</span></span>"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Tuy nhiên có 2 điểm cần lưu ý, đầu tiên là function này không có tên (rõ ràng ), thứ hai là kết thúc của nó luôn là một dấu chấm phẩy phía sau dấu mở ngoặc cuối cùng kia kìa.
Nhưng sử dụng kiểu gì? Vì khi chúng ta muốn sử dụng một function, chúng ta sẽ gọi đến tên của nó, còn function mà không có tên thì gọi vào mắt à???
Gán biến cho Anonymous Function
AF (Anonymous Function) có thể được gán cho một biến bất kỳ, biến này sao đó được gọi ra tương tự một function hay thậm chí có thể được push vào một mảng, và thế là ta có một mảng các function luôn, khá là hữu ích trong nhiều trường hợp mà mình chưa nghĩ ra :3
1 2 3 4 5 6 7 8 9 10 | <span class="token variable">$goodMorning</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token double-quoted-string string">"Good morning, <span class="token interpolation"><span class="token variable">$name</span></span>"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// gọi</span> <span class="token keyword">echo</span> <span class="token variable">$goodMorning</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Tony Stark'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//out put</span> Good morning<span class="token punctuation">,</span> Tony Stark |
Hay thậm chí là tạo ra hẳn một mảng các function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token variable">$ai</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token double-quoted-string string">"Good morning sir!"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token double-quoted-string string">"What can I do for you, sir?"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token punctuation">]</span> <span class="token comment">// Gọi</span> <span class="token variable">$ai</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//Out put</span> What can I <span class="token keyword">do</span> <span class="token keyword">for</span> you<span class="token punctuation">,</span> sir<span class="token operator">?</span> |
Tạo ra một Closure (Thứ mà chúng ta sẽ tìm hiểu trong một bài viết khác)
Cuối cùng thứ quan trọng nhất, làm một callback functioin
Callback Function
Đây gần như là chức năng quan trọng nhất của một AF, cho bạn nào còn chưa biết thế nào là callback thì nó là một function được đưa vào một function khác dưới dạng một tham số và function này có thể sử dụng các local scope trong function mà nó được đưa vào.
Hãy xem qua ví dụ dưới đây:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token keyword">function</span> <span class="token function">showText</span><span class="token punctuation">(</span><span class="token variable">$string</span><span class="token punctuation">,</span> <span class="token variable">$callback</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$result</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'upper'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token function">strtoupper</span><span class="token punctuation">(</span><span class="token variable">$string</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token single-quoted-string string">'lower'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token function">strtolower</span><span class="token punctuation">(</span><span class="token variable">$string</span><span class="token punctuation">)</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">is_callable</span><span class="token punctuation">(</span><span class="token variable">$callback</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">call_user_func</span><span class="token punctuation">(</span><span class="token variable">$callback</span><span class="token punctuation">,</span> <span class="token variable">$result</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">showText</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Tony Stark'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token variable">$name</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'upper'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//output</span> <span class="token constant">TONY</span> <span class="token constant">STARK</span> |
Trong ví dụ này, tham số thứ 2 đưa vào function showText chính làm một Callback function được viết dưới dạng một Anonymous Function.
Có bạn sẽ thằng mắc rằng trong ví dụ trên, callback đã hoạt động thế nào?
Giải thích:
- Đầu tiên khi
showText
được gọi, tham số đầu tiên của nó là'Tony Stark'
được đưa vào dưới biến$string
,$string
được đưa vào mảng$result
để xử lý. - Nếu có tham số thứ 2 truyền vào thì
if
sẽ kiểm tra nó có phải là một function hay không, nếu có thì gọicall_user_func
để bind local scope$result
thành tham số$name
của callback. - Lúc nào ta có
$name
chính là$result
và có thể gọi nó ra như bình thường.
Như có thể thấy, một callback trong PHP về cơ bản thì vẫn khá là giống với JS và bạn có hàng tá cách sử dụng với nó (mà bạn vẫn dùng hàng ngày) mà bạn có thể nghĩ ra, hoặc nếu không thì PHP cũng đã defined một lô các function mà có thể bạn không biết :v
array_map()
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:
1 2 3 4 5 6 7 8 9 | <span class="token comment">//array</span> <span class="token variable">$names</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token single-quoted-string string">'tony'</span><span class="token punctuation">,</span> <span class="token single-quoted-string string">'wanda'</span><span class="token punctuation">,</span> <span class="token single-quoted-string string">'captain'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token function">print_r</span><span class="token punctuation">(</span><span class="token function">array_map</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token double-quoted-string string">"Xin chao "</span> <span class="token punctuation">.</span> <span class="token function">ucfirst</span><span class="token punctuation">(</span><span class="token variable">$name</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> names<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//output</span> <span class="token punctuation">[</span><span class="token number">0</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token single-quoted-string string">'Xin chao Tony'</span><span class="token punctuation">,</span> <span class="token number">1</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token single-quoted-string string">'Xin chao Wanda'</span><span class="token punctuation">,</span> <span class="token number">2</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token single-quoted-string string">'Xin chao Captain'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> |
array_filter()
Tương tự như trên, function này 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 foreach
và if
1 2 3 4 5 6 7 8 9 10 11 | <span class="token variable">$input</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token variable">$output</span> <span class="token operator">=</span> <span class="token function">array_filter</span><span class="token punctuation">(</span><span class="token variable">$input</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$item</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token variable">$item</span> <span class="token operator">%</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">print_r</span><span class="token punctuation">(</span><span class="token variable">$output</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//output</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span> |
Và đương nhiên thứ mà bạn thấy rất nhiều trong Laravel: collect()->map(function() { ... })
và collect()->filter(function () { ... })
cũng chính là từ 2 function trên mà ra.
Lan man
Có một câu hỏi mà mình đã tự hỏi là, liệu callback trong PHP có thể bị hell
như trong JS??
Ý kiến cá nhân của mình thì là không, vì callback trong JS được sử dụng rất nhiều, nhất là khi code được xử lý bất đồng bộ kém. Còn với PHP, một ngôn ngữ có sự đồng bộ từ trên xuống dưới nên điều này sẽ khó có thể xảy ra nếu không muốn nói là không thể.
Còn ý kiến của các bạn thì sao? Hãy cho mình biết dưới phần comment, xin cám ơn đã theo dõi bài viết!