Bộ câu hỏi phỏng vấn PHP phần 4

Phân biệt giữa exception và error?


Việc khôi phục từ error là không thể. Giải pháp duy nhất cho các error là chấm dứt việc thực thi. Bạn có thể khôi phục từ exception bằng cách sử dụng khối try-catch hoặc thảy lại exception cho caller. Bạn sẽ không thể xử lý error bằng cách sử dụng khối try-catch. Ngay cả khi bạn xử lý chúng bằng cách sử dụng khối try-catch, ứng dụng của bạn sẽ không phục hồi nếu chúng xảy ra. Mặt khác, các exception có thể được xử lý bằng cách sử dụng các khối try-catch và có thể làm cho luồng chương trình trở nên bình thường nếu chúng xảy ra. Các exception liên quan đến ứng dụng, còn error liên quan đến môi trường mà ứng dụng đang chạy

Tối đa bao nhiêu đối số được phép trong một hàm trong PHP?


Không có giới hạn nhưng bạn có thể sử dụng func_get_args(), func_get_arg()func_num_args() để tránh viết tất cả các đối số trong định nghĩa hàm.

Sự khác biệt giữa trình thông dịch PHP và trình xử lý PHP là gì?


Trình xử lý PHP (PHP Handler) là một Apache module được Apache sử dụng để giao tiếp với trình thông dịch PHP (PHP Interpreter). Về cơ bản, nó được Apache sử dụng để xử lý các yêu cầu đối với tệp PHP. Có nhiều loại PHP Handlers khác nhau. Ví dụ mod_php là một Apache module cho PHP. mod_fcgid cho phép giao tiếp với trình thông dịch php_fpm qua TCP hoặc Unix socket.

Trình thông dịch PHP (PHP Interpreter) là một ứng dụng thực thi mã PHP một dòng tại một thời điểm. Đầu ra của trình thông dịch PHP được gửi đến trình xử lý PHP. Đầu ra này có thể được xử lý bởi các Apache module khác như mod_deflate hoặc mod_security. Đầu ra cuối cùng được gửi ra khỏi TCP socket mà Apache lắng nghe trên đó.

Sự khác biệt giữa việc sử dụng self và $this là gì?


Sử dụng $this để tham chiếu đến đối tượng hiện tại. Sử dụng self để tham chiếu đến lớp hiện tại. Nói cách khác, sử dụng $this->member cho các thành viên non-static, sử dụng self::$member cho các thành viên static.

Có một khía cạnh khác của self:: đáng nói đến. Bản thân self:: tham chiếu đến phạm vi ở điểm định nghĩa chứ không phải ở điểm thực thi. PHP 5.3 có một giải pháp, toán tử static:: thực hiện "late static binding", đây là một cách nói hay để nói rằng nó bị ràng buộc với phạm vi của lớp được gọi. Vì vậy, $this-> tham chiếu đến đối tượng hiện tại (một instance của một lớp), trong khi static:: tham chiếu đến một lớp.

Khi nào chúng ta nên sử dụng require_once thay vì require?


Câu lệnh require_once() giống hệt với require() ngoại trừ PHP sẽ kiểm tra xem tệp đã được include chưa và nếu có, sẽ không include (require) lại tệp đó. Đề xuất của tôi là sử dụng require_once 99,9% thời gian. Thay vào đó, việc sử dụng require hoặc include ngụ ý rằng mã của bạn không thể sử dụng lại được ở nơi khác, tức là các đoạn mã bạn đang lấy thực sự thực thi mã thay vì tạo sẵn một lớp hoặc một số thư viện hàm.

Có lý do gì để sử dụng strcmp() để so sánh string không?


Lý do sử dụng nó là vì strcmp trả về < 0 nếu str1 nhỏ hơn str2; > 0 nếu str1 lớn hơn str2 và 0 nếu chúng bằng nhau. === chỉ trả về true hoặc false, nó không cho bạn biết đâu là string "lớn hơn".

Sự khác biệt giữa MySQL, MySQLi và PDO là gì?


Có (hoặc hơn) ba cách phổ biến để sử dụng MySQL từ PHP:

  • (DEPRECATED) Các hàm mysql là thủ tục (procedure) và sử dụng thoát theo cách thủ công.
  • MySQLi là một sự thay thế cho các hàm mysql, với các phiên bản thủ tục và hướng đối tượng. Nó có hỗ trợ cho các câu lệnh được chuẩn bị sẵn (prepared statement).
  • PDO (PHP Data Objects) là một lớp trừu tượng cơ sở dữ liệu chung với sự hỗ trợ cho MySQL trong số nhiều cơ sở dữ liệu khác. Nó cung cấp các câu lệnh được chuẩn bị sẵn và tính linh hoạt đáng kể trong cách mà dữ liệu được trả về.

Tôi khuyên bạn nên sử dụng PDO với các câu lệnh được chuẩn bị sẵn. Nó là một API được thiết kế tốt và sẽ cho phép bạn dễ dàng di chuyển sang cơ sở dữ liệu khác (bao gồm bất kỳ cơ sở dữ liệu nào hỗ trợ ODBC) nếu cần thiết.

Một số thay đổi lớn mà PHP đã trải qua trong vài năm qua là gì?


  • PHP 5.0 đã hiện thực hóa mô hình đối tượng (AKA OOP).
  • PHP 5.1 đã thêm PDO - để truy cập cơ sở dữ liệu.
  • PHP 5.3 - bổ sung hỗ trợ namespace và các ràng buộc tĩnh trễ (late static bindings).

Toán tử Nullish Coalescing dùng để làm gì?


Toán tử Nullish Coalescing trả về toán hạng đầu tiên của nó nếu nó tồn tại và không phải là NULL. Nếu không, nó trả về toán hạng thứ hai của nó.

Ví dụ:

$name = $firstName ?? $username ?? $placeholder ?? "Guest";

Các lớp tự động tải (autoloading class) trong PHP là gì?


Với trình tải tự động (autoloader), PHP cho phép cơ hội cuối cùng để tải lớp hoặc interface trước khi nó bị lỗi. Hàm spl_autoload_register() trong PHP có thể đăng ký bất kỳ số lượng trình tải tự động nào, cho phép các lớp và interface tự động tải ngay cả khi chúng là undefined.

spl_autoload_register(function ($classname) {
   include $classname . '.php';
});
$object = new Class1();
$object2 = new Class2();

Trong ví dụ trên, chúng ta không cần "include" Class1.phpClass2.php. Hàm spl_autoload_register() sẽ tự động tải Class1.phpClass2.php.

Kể tên các hàm của lớp Exception?


Có các hàm sau có thể được sử dụng từ lớp Exception.

  • getMessage() - thông báo exception.
  • getCode() - mã exception.
  • getFile() - tên tệp nguồn (source filename).
  • getLine() - dòng nguồn (source line).
  • getTrace() - n mảng của backtrace().
  • getTraceAsString() - chuỗi theo dõi đã định dạng.

Exception::\_\_ toString cung cấp cho biểu diễn chuỗi của exception.

PHP có hỗ trợ nạp chồng phương thức không?


Nạp chồng phương thức (method overloading) là hiện tượng sử dụng cùng một tên phương thức với các tham số khác nhau (khác kiểu dữ liệu, khác số lượng tham số). Bạn không thể nạp chồng các hàm PHP. Chữ ký hàm (function signatures) chỉ dựa trên tên của chúng và không bao gồm danh sách đối số, vì vậy bạn không thể có hai hàm có cùng tên. Tuy nhiên, bạn có thể khai báo một hàm variadic có một số lượng đối số thay đổi. Bạn sẽ sử dụng func_num_args()func_get_arg() để truyền các đối số và sử dụng chúng bình thường.

function myFunc() {
   for ($i = 0; $i < func_num_args(); $i++) {
      printf("Argument %d: %s\n", $i, func_get_arg($i));
   }
}

/*
Argument 0: a
Argument 1: 2
Argument 2: 3.5
*/

myFunc('a', 2, 3.5);

Phân biệt giữa được parameterised function và non-parameterised function?


  • Non-parameterised function không nhận bất kỳ tham số nào tại thời điểm gọi.
  • Parameterised function nhận một hoặc nhiều đối số trong khi gọi. Chúng được sử dụng tại runtime của chương trình khi đầu ra phụ thuộc vào các giá trị được đưa ra tại runtime. Có hai cách để truy cập parameterised function:
    • call by value (ở đây chúng ta truyền trực tiếp giá trị).
    • call by reference (ở đây chúng ta truyền vị trí địa chỉ nơi giá trị được lưu trữ).

Giải thích việc hàm được gọi bằng tham chiếu (call by reference)?


Trong trường hợp call by reference, giá trị thực được sửa đổi nếu nó được sửa đổi bên trong hàm. Trong trường hợp này, chúng ta cần sử dụng ký hiệu & với các đối số chính thức. Ký hiệu & đại diện cho tham chiếu của biến.

Ví dụ:

function adder(&$str2) {
   $str2 .= 'Call By Reference';
}
$str = 'This is ';
adder($str);
echo $str; // output: This is Call By Reference

Tại sao chúng ta sử dụng extract()?


Hàm extract() nhập các biến vào bảng ký hiệu cục bộ từ một mảng. Hàm này sử dụng các key của mảng làm tên biến và giá trị làm giá trị biến. Đối với mỗi phần tử, nó sẽ tạo ra một biến trong bảng ký hiệu hiện tại. Hàm này trả về số lượng biến được trích xuất khi thành công.

$a = "Original";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";

// output: $a = Cat; $b = Dog; $c = Horse

Lưu trữ một mảng dưới dạng JSON hay dưới dạng một mảng được tuần tự hóa?


Bạn cần lưu trữ một mảng dữ liệu liên kết đa chiều trong một tệp phẳng cho mục đích lưu vào bộ nhớ đệm (caching). Giải pháp của bạn là gì? Hãy giải thích.

Giải pháp:

JSON đơn giản hơn và nhanh hơn so với định dạng tuần tự hóa của PHP và nên được sử dụng trừ khi:

  • Bạn đang lưu trữ các mảng lồng nhau sâu json_decode(): "Hàm này sẽ trả về false nếu dữ liệu được mã hóa JSON sâu hơn 127 phần tử."
  • Bạn đang lưu trữ các đối tượng cần được đảo ngược tuần tự hóa thành lớp chính xác. JSON không có bộ nhớ về lớp ban đầu của đối tượng là gì (chúng luôn được khôi phục dưới dạng các instance của stdClass).
  • Bạn không thể tận dụng **sleep()**wakeup() với JSON.
  • Bạn đang tương tác với các phiên bản PHP cũ không hỗ trợ json_decode.

Giải thích một closure trong PHP là gì và tại sao nó sử dụng mã định danh “use”?


Hãy xem xét đoạn mã dưới đây:

public function getTotal($tax)
{
   $total = 0.00;

   $callback =
      function ($quantity, $product) use ($tax, &$total)
      {
         $pricePerItem = constant(__CLASS__ . "::PRICE_" .
         strtoupper($product));
         $total += ($pricePerItem * $quantity) * ($tax + 1.0);
      };

   array_walk($this->products, $callback);
   return round($total, 2);
}

Bạn có thể giải thích tại sao sử dụng nó không?

Giải pháp:

Đây là cách PHP thể hiện một closure. Về cơ bản, điều này có nghĩa là bạn đang cho phép hàm ẩn danh "nắm bắt" các biến cục bộ (trong trường hợp này là $tax và một tham chiếu đến $total) bên ngoài phạm vi của nó và bảo toàn các giá trị của chúng như trạng thái (state) trong chính hàm ẩn danh. Một closure là một namespace riêng biệt, thông thường, bạn không thể truy cập các biến được xác định bên ngoài namespace này.

  • use cho phép bạn truy cập (sử dụng) các biến kế tiếp bên trong closure.
  • use là ràng buộc sớm. Điều đó có nghĩa là các giá trị biến được sao chép khi định nghĩa closure. Vì vậy, việc sửa đổi $tax bên trong bao đóng không có tác dụng bên ngoài, trừ khi nó là một con trỏ, giống như một đối tượng.
  • Bạn có thể truyền vào các biến dưới dạng con trỏ như trong trường hợp &$total. Bằng cách này, việc sửa đổi giá trị của $total sẽ gây tác động bên ngoài làm cho giá trị của biến ban đầu thay đổi.
Avatar Techmely Team
VIẾT BỞI

Techmely Team