Sử dụng tham số và biến với hàm trong PHP

    0

    Cách sử dụng tham số và biến khi làm việc với hàm trong PHP có nhiều đặc điểm gây khó khăn cho các bạn xuất phát từ các ngôn ngữ như C#. Trong bài học này chúng ta sẽ trao đổi chi tiết về các vấn đề như phạm vi của biến, truyền tham biến/tham trị, tham số mặc định, tham số biến động. Đây là những chủ đề tương đối khó hiểu nếu bạn chưa từng gặp ở ngôn ngữ khác.

    Hàm và phạm vi tác dụng của biến

    Như đã học trong bài về biến trong PHP, trong mỗi file script bạn có thể sử dụng một biến ở bất kỳ vị trí nào, miễn là sau vị trí nó được khai báo/khởi tạo. Trong trường hợp này người ta nói rằng, biến có phạm vi tác dụng là toàn bộ script đang chạy.

    Phạm vi tác dụng của biến

    Phạm vi tác dụng (scope) của một biến là tất cả những vị trí trong script mà bạn có thể sử dụng được biến đó.

    Hãy xem tình huống sau:

    $name = 'Donald Trump';
    function welcome_1() {
        echo "Hello, $name. Welcome to heaven!"; // đây là $name nào?
    }
    function welcome_2() {
        $name = 'Bill Clinton'; // đây là $name nào?
        echo "Hello, $name. Welcome to hell!";
    }
    function welcome_3($name) {
        echo "Hello, $name. Welcome to earth"; // đây là $name nào?
    }

    Trong script trên chúng ta tạo một biến $name với giá trị ‘Donald Trump’ và ba hàm. Hàm welcome_1 sử dụng trực tiếp biến $name trong lệnh echo. Trong hàm welcome_2 chúng ta gán $name = ‘Bill Clinton’ trước khi gọi echo. Trong hàm welcome_3 chúng ta lại đặt $name làm tham số của hàm và sử dụng cùng lệnh echo.

    Vậy biến $name trong các hàm này có giống nhau hay không, và giá trị của $name trong mỗi trường hợp ra sao.

    Để trả lời vấn đề này chúng ta cần biết quy tắc xác định phạm vi của biến trong và ngoài hàm.

    Biến cục bộ và biến toàn cục

    Tất cả các biến khai báo trong script nhưng không nằm trong hàm được gọi là biến toàn cục (global variable). Trong ví dụ ở trên, biến $name khai báo đầu tiên với giá trị ‘Donald Trump’ là một biến toàn cục.

    Biến toàn cục có phạm vi tác dụng là toàn bộ script đó, tính từ vị trí khai báo, nhưng không tính trong thân các hàm.

    Như vậy biến $name toàn cục (giá trị ‘Donald Trump’) chỉ có tác dụng bên ngoài các hàm (vùng màu vàng trong hình). Code bên trong hàm (vùng màu lam) không biết gì về sự tồn tại của $name. Điều này có nghĩa là hàm welcome_1 sẽ gặp cảnh báo lỗi “Undefined variable ‘$name'” – sử dụng biến chưa được định nghĩa.

    Biến khai báo bên trong một hàm được gọi là biến cục bộ (local variable). Biến cục bộ chỉ có tác dụng bên trong khối code thân hàm. Code bên ngoài hàm không biết gì về sự tồn tại của biến cục bộ. Thân hàm tạo ra một “không gian” riêng trong đó mặc định không cho phép nhìn và sử dụng các biến toàn cục.

    Như vậy, trong hàm welcome_2, biến $name = ‘Bill Clinton’ là một biến cục bộ. Code trong hàm này chỉ biết đến biến cục bộ $name vừa khai báo. Do vậy lệnh echo sẽ in ra lời chào mừng Bill Clinton.

    Tham số của hàm được sử dụng trong hàm với cùng vai trò như một biến cục bộ. Do vậy trong hàm welcome_3, tham số $name coi như một biến cục bộ. Tuy nhiên, giá trị của tham số chỉ xuất hiện trong lời gọi hàm.

    Sử dụng biến toàn cục trong hàm, từ khóa global

    Mặc định trong hàm không sử dụng được biến toàn cục. Tuy nhiên PHP vẫn cho phép sử dụng biến toàn cục trong hàm. Để làm điều này bạn cần chỉ định rõ ràng biến toàn cục nào sẽ được sử dụng trong hàm.

    Quay lại với hàm welcome_1, nếu muốn sử dụng biến toàn cục $name bạn cần viết lại code như sau:

    $name = 'Donald Trump';
    function welcome_1() {
        global $name;
        echo "Hello, $name. Welcome to heaven!"; // đây là $name nào?
    }

    Dòng lệnh global $name; chỉ định cần dùng biến toàn cục $name bên trong hàm. Do vậy, tất cả lệnh tiếp sau sẽ sử dụng được biến $name (toàn cục).

    Tham biến và tham trị

    Khi định nghĩa một hàm chúng ta cung cấp danh sách tham số hình thức. Tham số hình thức là một dạng quy ước về những thông tin mà hàm có thể nhận và sử dụng.

    Tham số hình thức có thể xem là những biến mà chúng ta có thể sử dụng trong thân hàm. Khi sử dụng (gọi) hàm chúng ta cung cấp giá trị (tham số thực) của các tham số tương ứng.

    Tuy nhiên những gì diễn ra khi truyền tham số thực trong lời gọi hàm (ở runtime) là tương đối phức tạp.

    Trước hết chúng ta nên hình dung mỗi hàm khi hoạt động (ở runtime) là một không gian riêng đóng kín. Không gian này giao tiếp với không gian bên ngoài (chương trình) thông qua: (1) các tham số – giúp chuyển thông tin từ ngoài vào hàm; (2) lệnh trả kết quả return – giúp chuyển thông tin từ trong hàm ra ngoài.

    Có hai cách thức chuyển thông từ ngoài vào (và cũng có hai cách chuyển thông tin từ trong ra).

    (1) tạo bản sao: đây là cách mặc định và đơn giản hơn. PHP tạo ra bản sao của dữ liệu đó và truyền vào cho hàm 1 bản sao. Tất cả những tác động trên dữ liệu đầu vào thực tế chỉ tác động lên bản sao, và do đó, không ảnh hưởng đến bản chính. Cách thức truyền tham số này gọi là truyền giá trị.

    Loại tham số sử dụng lối truyền giá trị cũng được gọi tắt là tham trị.

    Do đây là cơ chế mặc định, khi định nghĩa hàm bạn không cần chỉ định gì khác trên tham số.

    (2) truyền bản gốc: trong cơ chế này, PHP truyền thẳng bản gốc của dữ liệu cho hàm. Tất cả những gì bên trong hàm thực hiện trên dữ liệu thực chất sẽ tác động lên bản gốc. Cơ chế này có tên gọi là truyền tham chiếu. Loại tham số sử dụng lối truyền tham chiếu được gọi tắt là tham biến.

    Để yêu cầu PHP truyền tham chiếu (bản gốc) bạn phải chỉ định rõ khi định nghĩa hàm:

    function goodbye(&$greeting) {
        $greeting = "See you later!";
    }
    $greeting = "";
    goodbye($greeting);
    echo $greeting;

    Hãy để ý trước tham số $greeting có ký tự &. Đặt ký tự & trước một tham số sẽ yêu cầu PHP truyền tham chiếu cho tham số tương ứng.

    Trong ví dụ nhỏ này, ban đầu biến $greeting là một chuỗi rống. Sau khi gọi hàm goodbye (và truyền $greeting), chuỗi này nhận giá trị mới “See you later!”.

    Lưu ý rằng,

    • Nếu một tham số yêu cầu truyền tham chiếu, bạn bắt buộc phải cung cấp 1 biến trong lời gọi hàm chứ không thể cung cấp 1 giá trị cụ thể.
    • Nếu tham số yêu cầu truyền giá trị, bạn có thể cung cấp cả biến lẫn giá trị cụ thể trong lời gọi hàm.

    Đối với dữ liệu kiểu object, cơ chế truyền tham số mặc định lại là truyền tham chiếu. Chúng ta sẽ học về object trong phần lập trình hướng đối tượng.

    Tham số mặc định

    Hãy cùng thực hiện ví dụ sau:

    function equation($a, $b = 0, $c = 0){
        $d = $b*$b - 4*$a*$c;
        if($d < 0) return false;
        return [
            'x1' => (-$b + sqrt($d))/(2*$a),
            'x2' => (-$b - sqrt($d))/(2*$a)
        ];
    }
    print_r(equation(1, 2, 1)); // lời gọi có đủ 3 tham số
    print_r(equation(1, 2 )); // lời gọi này chỉ có tham số cho $a và $b
    print_r(equation(1)); // lời gọi này chỉ có tham số cho $a

    Đây là ví dụ về cách xây dựng và sử dụng hàm giải phương trình bậc hai. Kết quả chạy script trên như sau:

    Array
    (
        [x1] => -1
        [x2] => -1
    )
    Array
    (
        [x1] => 0
        [x2] => -2
    )
    Array
    (
        [x1] => 0
        [x2] => 0
    )

    Hãy để ý danh sách tham số có điểm đặc biệt ($a, $b = 0, $c = 0): mỗi tham số được gán luôn giá trị.

    Cách viết tham số trong định nghĩa hàm như trên được gọi là tham số mặc định (default parameter).

    Tham số mặc định là những tham số được gán sẵn giá trị. Giá trị gán sẵn này cũng gọi là giá trị mặc định của tham số đó.

    Do tham số được PHP đọc và sử dụng từ trái qua phải, nếu có cả tham số bắt buộc và tham số mặc định, bạn cần đặt tham số mặc định đứng sau tham số bắt buộc.

    Hãy nhìn lại ví dụ trên, tham số bắt buộc $a nằm đầu tiên, sau đó mới đến các tham số mặc định $b = 1, $c = 1.

    Nếu bạn đặt tham số bắt buộc đứng sau tham số mặc định, các IDE sẽ nhắc nhở.

    Khi gọi hàm với tham số mặc định bạn có quyền lựa chọn cung cấp giá trị cho tham số tương ứng hoặc bỏ qua tham số đó. Khi bạn bỏ qua tham số (không cung cấp giá trị), PHP sẽ sử dụng giá trị mặc định.

    Khi quyết định bỏ qua các tham số mặc định trong lời gọi hàm, bạn chỉ có thể bỏ lần lượt từ phải qua trái. Ví dụ, với danh sách tham số ($a, $b=1, $c=1), bạn nếu bỏ 1 tham số thì PHP sẽ hiểu đó là tham số cuối cùng (bên phải) – tham số $c. Nếu bỏ hai tham số – đó là $c rồi $b.

    print_r(equation(1, 2, 1)); // lời gọi có đủ 3 tham số
    print_r(equation(1, 2 )); // lời gọi này chỉ có tham số cho $a và $b, bỏ qua $c
    print_r(equation(1)); // lời gọi này chỉ có tham số cho $a, bỏ qua $c và $b

    Hàm với lượng tham số tùy ý

    Trong bài học trước, khi trình bày cú pháp khai báo hàm, chúng ta có nói rằng, một hàm có thể không nhận tham số và có thể để trống danh sách tham số.

    Tuy nhiên, thực tế không hoàn toàn như vậy.

    Trong PHP, một hàm để trống danh sách tham số có thể nhận lượng tham số tùy ý, từ không có tham số, đến không giới hạn số tham số.

    Hãy xem ví dụ sau:

    function sum() {
        $args = func_get_args();
        $s = 0;
        foreach ($args as $num) {
            if (is_numeric($num))
                $s += $num;
        }
        return $s;
    }
    echo sum(1, 2, 3, 4, 5); // kết quả 15
    echo sum(1, 2, 3, '4', 'abc', 5); // kết quả 15

    Hàm sum có khả năng tính tổng của bất kỳ tham số nào.

    Trong ví dụ trên chúng ta định nghĩa hàm sum với danh sách tham số rỗng. Tuy nhiên khi gọi hàm chúng ta cung cấp tham số tùy ý. Khi chạy sum ở cả hai trường hợp đều không gây lỗi gì!

    Trong PHP, danh sách tham số trong nhiều trường hợp chỉ mang tính hình thức. PHP cho phép bạn truyền bất kỳ thứ gì cho hàm, miễn là hàm đó có khả năng xử lý. Nói cách khác, việc truyền tham số “lung tung” cho hàm không dẫn đến lỗi.

    PHP cung cấp các hàm đặc biệt mà nếu dùng trong hàm, chúng sẽ cho biết các thông tin về tham số của chính hàm đó:

    $array = func_get_args(); 
    $count = func_num_args();
    $value = func_get_arg(argument_number);

    Trong thân hàm sum chúng ta sử dụng hàm func_get_args. Hàm này chuyển danh sách tham số về một mảng kết hợp trong đó khóa là tên biến, và giá trị là giá trị của biến tương ứng.

    Từ đây bạn có thể duyệt qua mảng tham số này để quyết định làm những gì. Trong hàm sum, chúng ta chọn những tham số có giá trị số (hoặc chuỗi chứa toàn số) để cộng dồn vào một biến $s – tổng.

    Điều này cũng dẫn đến một vấn đề cần lưu ý: trong PHP, điều quan trọng hơn cả là cách thức hàm xử lý tham số, chứ không phải bản thân danh sách tham số. Nghĩa là, tham số trong định nghĩa hàm và trong lời gọi hàm không bắt buộc phải phù hợp. Miễn sao hàm xử lý được!

    Chỉ dẫn kiểu (type hint)

    Như bạn đã thấy trong các phần trên, khi định nghĩa hàm chúng ta không cung cấp bất kỳ thông tin gì về kiểu của tham số và kiểu của kết quả. Điều này dẫn tới hệ quả là bạn có thể cung cấp dữ liệu thuộc bất kỳ kiểu nào khi gọi hàm.

    Nếu trong hàm không thực hiện kiểm tra và biến đổi kiểu phù hợp, việc thực hiện lệnh trên tham số thực với kiểu dữ liệu không phù hợp sẽ dẫn đến lỗi thực thi (runtime error).

    PHP cung cấp một tính năng đặc biệt: chỉ dẫn kiểu (type hinting). Chỉ dẫn kiểu là cung cấp thông tin về kiểu của tham số và kiểu của kết quả khi định nghĩa hàm.

    Hãy xem ví dụ sau đây:

    function create_new_book(string $title,
                             string $authors,
                             string $publisher,
                             int $year): array {
        return [
            'title' => $title,
            'authors' => $authors,
            'publisher' => $publisher,
            'year' => $year
        ];
    }
    function print_book(array $book) {
        $title = $book['title'];
        $authors = $book['authors'];
        $publisher = $book['publisher'];
        $year = $book['year'];
        echo "$title [$authors] -$publisher, $year";
    }
    $book = create_new_book('PHP programming', 'Trump D.', 'Washington', 2020);
    print_book($book);

    Trong khai báo hàm create_new_book và print_book có điểm đặc biệt trong danh sách tham số:

    function create_new_book(string $title,
                             string $authors,
                             string $publisher,
                             int $year): array {
    ...
    }
    function print_book(array $book) {
    ...
    }

    Mỗi tham số giờ đây được khai báo với thông tin về kiểu đứng trước. Đây là cách sử dụng chỉ dẫn kiểu cho tham số.

    Đối với hàm create_new_book còn có điểm đặc biệt nữa, phần : array nằm giữa danh sách tham số và khối code thân hàm. Đây được gọi là phần chỉ dẫn kiểu kết quả của hàm.

    Khi sử dụng chỉ dẫn kiểu, các IDE sẽ sử dụng các thông tin này để giúp bạn kiểm soát kiểu của giá trị truyền vào ngay từ lúc viết code, dẫn tới hạn chế lỗi runtime do kiểu không phù hợp.

    Sử dụng chỉ dẫn kiểu còn có lợi ích nữa: PHP sẽ cố gắng chuyển đổi kiểu của tham số thực sang kiểu mong muốn trong chỉ dẫn kiểu.

    Khi sử dụng với chỉ dẫn kiểu cần lưu ý tên gọi của các kiểu có chút hơi khác: số nguyên – int, số thực – float, logic – bool, chuỗi – string, mảng – array.

    Kết luận

    Trong bài học này chúng ta đã tìm hiểu cách sử dụng biến và tham số trong hàm:

    • Biến trong PHP có phạm vi tác dụng. Hai phạm vi chúng ta đã biết là cục bộ (trong nội bộ hàm) và toàn cục (trong phạm vi script).
    • Mặc định hàm trong PHP không cho truy xuất biến toàn cục. Để truy xuất biến toàn cục trong hàm cần sử dụng từ khóa global.
    • PHP có hai cơ chế truyền tham số cho hàm: truyền tham chiếu và truyền giá trị. Để chỉ định truyền tham chiếu cần dùng ký tự & trước biến tương ứng.
    • PHP cho phép cung cấp giá trị mặc định cho tham số, qua đó có thể bỏ qua tham số tương ứng trong lời gọi hàm.
    • PHP cho phép truyền tham số bất kỳ cho hàm. Điều quan trọng là trong hàm có cách thức xử lý tham số phù hợp.

    + Nếu bạn thấy site hữu ích, trước khi rời đi hãy giúp đỡ site bằng một hành động nhỏ để site có thể phát triển và phục vụ bạn tốt hơn.
    + Nếu bạn thấy bài viết hữu ích, hãy giúp chia sẻ tới mọi người.
    + Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần thảo luận cuối trang.
    Cảm ơn bạn!

    Subscribe
    Notify of
    guest
    0 Thảo luận
    Inline Feedbacks
    View all comments