Làm thế nào để giải quyết vấn đề phải là một thể hiện của chuỗi, chuỗi được đưa ra trước khi có PHP 7?


217

Đây là mã của tôi:

function phpwtf(string $s) {
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");

Điều này dẫn đến lỗi này:

Lỗi nghiêm trọng có thể bắt được: Đối số 1 được truyền cho phpwtf () phải là một thể hiện của chuỗi, chuỗi đã cho

Thật hơn một chút Orwellian khi thấy PHP nhận ra và từ chối loại mong muốn trong cùng một hơi thở. Có năm đèn, chết tiệt.

Tương đương với kiểu gợi ý cho các chuỗi trong PHP là gì? Thưởng xem xét cho câu trả lời giải thích chính xác những gì đang xảy ra ở đây.


5
Vâng, đó là bởi vì bạn đang làm sai. Mã của bạn không phải hoạt động, để bắt đầu. Đọc về cách tung hứng trong các tài liệu PHP. PHP là kiểu gõ động và gõ yếu. Bạn có thể sử dụng (chuỗi) để truyền đối số thành chuỗi (chỉ trong thân hàm) nhưng bạn chỉ có thể gợi ý các đối tượng và mảng giống như bạn làm trong đoạn mã của mình.
Richard Knop

7
Vấn đề là bạn đã phạm một lỗi nhỏ. Có bốn đèn!
CJ Dennis

@Gordon, tôi đã thử nghiệm trên 5.6. Vẫn không có may mắn.
Pacerier

@Pacerier Vui lòng theo dõi wiki.php.net/rfc để biết những phát triển mới nhất.
Gordon

3
Rõ ràng, gợi ý kiểu vô hướng (như OP trực giác dự kiến ​​là một thứ ở trên) cuối cùng đã được phê duyệt theo RFC cho PHP * 7 * theo nguồn . RFC được phê duyệt rõ ràng cũng cung cấp đường cú pháp cho các giá trị trả về kiểm tra kiểu cũng như các tham số (đối số). Đó là một thời gian dài sắp tới.
SeldomNeedy

Câu trả lời:


204

Trước khi gợi ý loại 7 PHP chỉ có thể được sử dụng để buộc các loại đối tượng và mảng. Các loại vô hướng không phải là loại gợi ý. Trong trường hợp này, một đối tượng của lớp stringđược mong đợi, nhưng bạn đang cho nó một (vô hướng) string. Thông báo lỗi có thể buồn cười, nhưng không nên bắt đầu với nó. Với hệ thống gõ động, điều này thực sự có ý nghĩa biến thái.

Bạn chỉ có thể bằng tay "loại gợi ý" loại vô hướng:

function foo($string) {
    if (!is_string($string)) {
        trigger_error('No, you fool!');
        return;
    }
    ...
}

1
@deceze, Có một cú pháp cho gợi ý loại ngược? Ví dụ, bất cứ điều gì trừ mảng.
Pacerier

@Pacerier Không, không có.
lừa dối

4
Câu trả lời này không hợp lệ đối với PHP 7
Jose Nobile

24

Từ hướng dẫn của PHP :

Gợi ý loại chỉ có thể là loại đối tượng và mảng (kể từ PHP 5.1). Gợi ý kiểu truyền thống với int và chuỗi không được hỗ trợ.

Vì vậy, bạn có nó. Thông báo lỗi không thực sự hữu ích, tôi cung cấp cho bạn điều đó mặc dù.

** 2017 Chỉnh sửa **

PHP7 đã giới thiệu nhiều khai báo kiểu dữ liệu hàm và liên kết đã nói ở trên đã được chuyển sang đối số Hàm: Khai báo kiểu . Từ trang đó:

Các loại hợp lệ

  • Tên lớp / giao diện : Tham số phải là một thể hiện của tên lớp hoặc giao diện đã cho. (kể từ PHP 5.0.0)
  • self : Tham số phải là một thể hiện của cùng một lớp với phương thức được định nghĩa trên. Điều này chỉ có thể được sử dụng trên các phương thức lớp và thể hiện. (kể từ PHP 5.0.0)
  • mảng : Tham số phải là một mảng. (kể từ PHP 5.1.0) có thể gọi được Tham số phải là một cuộc gọi hợp lệ. PHP 5.4.0
  • bool : Tham số phải là giá trị boolean. (kể từ PHP 7.0.0)
  • float : Tham số phải là số dấu phẩy động. (kể từ PHP 7.0.0)
  • int : Tham số phải là số nguyên. (kể từ PHP 7.0.0)
  • chuỗi : Tham số phải là một chuỗi. (kể từ PHP 7.0.0)
  • iterable : Tham số phải là một mảng hoặc một thể hiện Traversable. (kể từ PHP 7.1.0)

Cảnh báo

Bí danh cho các loại vô hướng ở trên không được hỗ trợ. Thay vào đó, chúng được coi là tên lớp hoặc giao diện. Ví dụ: sử dụng boolean làm tham số hoặc kiểu trả về sẽ yêu cầu một đối số hoặc giá trị trả về là một thể hiện của lớp hoặc giao diện boolean, thay vì kiểu bool:

<?php
   function test(boolean $param) {}
   test(true);
 ?>

Ví dụ trên sẽ xuất ra:

 Fatal error: Uncaught TypeError: Argument 1 passed to test() must be an instance of boolean, boolean given, called in - on line 1 and defined in -:1

Cảnh báo cuối cùng thực sự có ý nghĩa để hiểu lỗi "Đối số phải có kiểu chuỗi, chuỗi đã cho"; do hầu hết chỉ có tên lớp / giao diện được phép làm loại đối số, PHP cố gắng định vị tên lớp "chuỗi", nhưng không thể tìm thấy vì đây là loại nguyên thủy, do đó không thành công với lỗi khó xử này.


8

PHP cho phép "gợi ý" nơi bạn cung cấp một lớp để chỉ định một đối tượng. Theo hướng dẫn sử dụng PHP, "Gợi ý loại chỉ có thể thuộc loại đối tượng và mảng (kể từ PHP 5.1). Gợi ý kiểu truyền thống với int và chuỗi không được hỗ trợ." Lỗi gây nhầm lẫn do bạn chọn "chuỗi" - đặt "myClass" vào vị trí của nó và lỗi sẽ đọc khác nhau: "Đối số 1 được truyền cho phpwtf () phải là một phiên bản của myClass, chuỗi đã cho"


3

Như những người khác đã nói, loại gợi ý hiện chỉ hoạt động cho các loại đối tượng. Nhưng tôi nghĩ rằng lỗi cụ thể mà bạn đã kích hoạt có thể là do chuẩn bị loại chuỗi SplString sắp tới .

Về lý thuyết, nó hoạt động giống như một chuỗi, nhưng vì nó là một đối tượng sẽ vượt qua xác minh loại đối tượng. Thật không may, nó chưa có trong PHP 5.3, có thể đến phiên bản 5.4, vì vậy chưa thử nghiệm điều này.


2

Tính đến PHP 7.0 khai báo kiểu cho phép các loại vô hướng, vì vậy các loại đang có sẵn: self, array, callable, bool, float, int, string. Ba cái đầu tiên có sẵn trong PHP 5, nhưng bốn cái cuối cùng mới trong PHP 7. Nếu bạn sử dụng bất cứ thứ gì khác (ví dụ integerhoặc boolean) sẽ được hiểu là tên lớp.

Xem hướng dẫn sử dụng PHP để biết thêm thông tin .


0

Có thể không an toàn và xinh đẹp nhưng nếu bạn phải:

class string
{
    private $Text;
    public function __construct($value)
    {
        $this->Text = $value;
    }

    public function __toString()
    {
        return $this->Text;
    }
}

function Test123(string $s)
{
    echo $s;
}

Test123(new string("Testing"));

5
Tôi vẫn có thể tạo mộtnew string(array(1,2,3))
Jimmy T.

0

Tôi đã gặp lỗi này khi gọi một hàm từ Bộ điều khiển Laravel đến tệp PHP.

Sau một vài giờ, tôi đã tìm thấy vấn đề: Tôi đã sử dụng $ this từ bên trong một hàm tĩnh.


Using $this when not in object contextthực sự là một thông điệp khó hiểu
Ben Fransen

0

(ban đầu được đăng bởi leepowers trong câu hỏi của mình)

Thông báo lỗi gây nhầm lẫn vì một lý do lớn:

Tên kiểu nguyên thủy không được bảo lưu trong PHP

Sau đây là tất cả các khai báo lớp hợp lệ:

class string { }
class int { }
class float { }
class double { }

Sai lầm của tôi là khi nghĩ rằng thông báo lỗi chỉ liên quan đến kiểu nguyên thủy chuỗi - từ 'dụ' nên đã khiến tôi phải tạm dừng. Một ví dụ để minh họa thêm:

class string { }
$n = 1234;
$s1 = (string)$n;
$s2 = new string();
$a = array('no', 'yes');
printf("\$s1 - primitive string? %s - string instance? %s\n",
        $a[is_string($s1)], $a[is_a($s1, 'string')]);
printf("\$s2 - primitive string? %s - string instance? %s\n",
        $a[is_string($s2)], $a[is_a($s2, 'string')]);

Đầu ra:

$ s1 - chuỗi nguyên thủy? có - ví dụ chuỗi? Không

$ s2 - chuỗi nguyên thủy? không có chuỗi ký tự? Đúng

Trong PHP, nó có thể stringlà một stringngoại trừ khi nó thực sự là một string. Như với bất kỳ ngôn ngữ nào sử dụng chuyển đổi kiểu ngầm định, ngữ cảnh là tất cả.


-1

Tôi nghĩ rằng typecasting trên php trên khối bên trong, String trên PHP không phải là đối tượng như tôi biết:

<?php
function phpwtf($s) {
    $s = (string) $s;
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");

2
Bạn có thể thêm xác thực is_opes () bên trong hàm của mình để ngăn giá trị khác được truyền cho hàm.
subosito

1
(string) $scó thể đưa ra lỗi nếu $slà một đối tượng không thể chuyển thành chuỗi (không có __toString()phương thức nào được thực hiện), vì vậy nó không dễ như vậy
Yanick Rochon

Có Yanick bạn đúng. Nhưng chúng ta không thể buộc tất cả các đầu vào là chuỗi phải không? đó là lý do tại sao ngoại lệ đến chơi. Chúng ta có thể kết hợp loại xác nhận và bắt ngoại lệ cho phần còn lại;)
subosito

Tôi chỉ nói rằng việc truyền một số biến thành chuỗi mà không cần kiểm tra trước nếu có thể tránh biến đó, chủ yếu là vì việc bắt ngoại lệ là tốn kém và dẫn đến các mẫu thiết kế / thói quen mã hóa xấu.
Yanick Rochon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.