วิธีการแก้ไข“ ต้องเป็นอินสแตนซ์ของสตริง, สตริงที่กำหนด” ก่อน PHP 7?


217

นี่คือรหัสของฉัน:

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

ผลลัพธ์ใดที่ทำให้เกิดข้อผิดพลาดนี้:

ข้อผิดพลาดร้ายแรงที่ตรวจจับได้: อาร์กิวเมนต์ 1 ส่งผ่านไปยัง phpwtf () ต้องเป็นอินสแตนซ์ของสตริง, สตริงที่กำหนด

เป็นมากกว่า Orwellian เล็กน้อยที่จะเห็น PHP จดจำและปฏิเสธประเภทที่ต้องการในลมหายใจเดียวกัน มีไฟอยู่ห้าดวง

อะไรคือสิ่งที่เทียบเท่าประเภทคำใบ้สำหรับสตริงใน PHP? การพิจารณาโบนัสสำหรับคำตอบที่อธิบายสิ่งที่เกิดขึ้นที่นี่อย่างแน่นอน


5
นั่นเป็นเพราะคุณทำผิด รหัสของคุณไม่ควรเริ่มทำงาน อ่านข้อมูลเกี่ยวกับการเล่นปาหี่ประเภทในเอกสาร PHP PHP เป็นแบบไดนามิกพิมพ์และพิมพ์อ่อนแอ คุณสามารถใช้ (สตริง) เพื่อโยนอาร์กิวเมนต์เป็นสตริง (เฉพาะในส่วนของฟังก์ชั่นเท่านั้น) แต่คุณสามารถบอกใบ้วัตถุและอาร์เรย์เช่นเดียวกับที่คุณทำในข้อมูลโค้ดของคุณ
Richard Knop

7
ปัญหาคือคุณทำผิดพลาดเล็กน้อย มีสี่ไฟ!
CJ Dennis

@ กอร์ดอนฉันทดสอบที่ 5.6 ยังไม่มีโชค
Pacerier

@Pacerier โปรดติดตามwiki.php.net/rfcสำหรับการพัฒนาล่าสุด
Gordon

3
เห็นได้ชัดว่าสเกลาประเภทพูดเป็นนัย (ตาม OP คาดว่าสังหรณ์ใจที่จะเป็นสิ่งที่เหนือ) ได้ในที่สุดได้รับการอนุมัติภายใต้ RFC สำหรับ PHP นี้ * 7 * ตามแหล่งที่มา เห็นได้ชัดว่า RFC ที่ได้รับการอนุมัตินั้นยังให้น้ำตาลซินแทคติคสำหรับการตรวจสอบผลตอบแทนประเภทรวมถึงพารามิเตอร์ (อาร์กิวเมนต์) มันเป็นเวลานานในการมา
SeldomNeedy

คำตอบ:


204

ก่อนหน้าการบอกกล่าวชนิด PHP 7 สามารถใช้เพื่อบังคับประเภทของวัตถุและอาร์เรย์เท่านั้น ประเภทสเกลาร์ไม่สามารถบอกใบ้ได้ ในกรณีนี้วัตถุของชั้นstringคาดว่า แต่คุณให้มัน string(เกลา) ข้อความแสดงข้อผิดพลาดอาจตลก แต่ไม่ควรเริ่มต้นด้วย ด้วยระบบการพิมพ์แบบไดนามิกสิ่งนี้ทำให้รู้สึกผิดเพี้ยนไปบ้าง

คุณสามารถ"ประเภทคำใบ้" ประเภทสเกลาร์ด้วยตนเองเท่านั้น:

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

1
@deceze มีไวยากรณ์สำหรับคำใบ้ประเภทย้อนกลับหรือไม่? เช่นอะไรก็ได้ยกเว้นอาร์เรย์
Pacerier

@Pacerier ไม่ไม่มี
หลอกลวง

4
คำตอบนี้ไม่ถูกต้องสำหรับ PHP 7
Jose Nobile

24

จากคู่มือของ PHP :

คำแนะนำประเภทสามารถเป็นประเภทวัตถุและอาร์เรย์ (ตั้งแต่ PHP 5.1) เท่านั้น ไม่รองรับการบอกกล่าวแบบดั้งเดิมด้วย int และสตริง

ดังนั้นคุณมีมัน ข้อความแสดงข้อผิดพลาดไม่เป็นประโยชน์จริง ๆ ฉันขอให้คุณว่า

** 2017 แก้ไข **

PHP7 แนะนำการประกาศชนิดข้อมูลฟังก์ชั่นมากขึ้นและการเชื่อมโยงดังกล่าวได้ถูกย้ายไปข้อโต้แย้งฟังก์ชั่น: การประกาศประเภท จากหน้านั้น:

ประเภทที่ถูกต้อง

  • ชื่อคลาส / อินเตอร์เฟส : พารามิเตอร์ต้องเป็นอินสแตนซ์ของชื่อคลาสหรืออินเตอร์เฟสที่กำหนด (ตั้งแต่ PHP 5.0.0)
  • self : พารามิเตอร์ต้องเป็นอินสแตนซ์ของคลาสเดียวกันกับวิธีที่กำหนดไว้ สามารถใช้กับวิธีการเรียนและอินสแตนซ์เท่านั้น (ตั้งแต่ PHP 5.0.0)
  • array : พารามิเตอร์ต้องเป็นอาร์เรย์ (ตั้งแต่ PHP 5.1.0) callable พารามิเตอร์ต้องเป็น callable ที่ถูกต้อง PHP 5.4.0
  • บูล : พารามิเตอร์จะต้องเป็นค่าบูลีน (ตั้งแต่ PHP 7.0.0)
  • ลอย : พารามิเตอร์จะต้องเป็นจำนวนจุดลอยตัว (ตั้งแต่ PHP 7.0.0)
  • int : พารามิเตอร์จะต้องเป็นจำนวนเต็ม (ตั้งแต่ PHP 7.0.0)
  • string : พารามิเตอร์จะต้องเป็นสตริง (ตั้งแต่ PHP 7.0.0)
  • iterable : พารามิเตอร์ต้องเป็นอาร์เรย์หรืออินสแตนซ์ของ Traversable (ตั้งแต่ PHP 7.1.0)

คำเตือน

ไม่รองรับนามแฝงสำหรับประเภทสเกลาร์ด้านบน แต่จะถือว่าเป็นชื่อคลาสหรืออินเตอร์เฟส ตัวอย่างเช่นการใช้บูลีนเป็นพารามิเตอร์หรือชนิดส่งคืนจะต้องมีอาร์กิวเมนต์หรือค่าส่งคืนที่เป็นอินสแตนซ์ของคลาสหรืออินเทอร์เฟซบูลีนมากกว่าประเภทบูล:

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

ตัวอย่างด้านบนจะแสดงผล:

 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

คำเตือนครั้งสุดท้ายมีความสำคัญอย่างยิ่งที่จะเข้าใจข้อผิดพลาด "อาร์กิวเมนต์ต้องเป็นสตริงประเภทสตริงที่กำหนด"; เนื่องจากชื่อคลาส / อินเตอร์เฟสส่วนใหญ่จะได้รับอนุญาตเป็นประเภทอาร์กิวเมนต์ PHP จึงพยายามค้นหาชื่อคลาส "string" แต่ไม่สามารถค้นหาได้เนื่องจากเป็นประเภทดั้งเดิมดังนั้นจึงล้มเหลวด้วยข้อผิดพลาดที่น่าอึดอัดใจนี้


8

PHP อนุญาตให้ "hinting" ที่คุณให้คลาสเพื่อระบุวัตถุ ตามคู่มือ PHP ระบุว่า "ประเภทคำแนะนำสามารถเป็นได้ทั้งวัตถุและอาร์เรย์ (ตั้งแต่ PHP 5.1) เท่านั้นไม่สนับสนุนประเภทดั้งเดิมที่บอกใบ้กับ int และสตริง" ข้อผิดพลาดเกิดความสับสนเนื่องจากคุณเลือก "string" - ใส่ "myClass" แทนและข้อผิดพลาดจะอ่านต่างกัน: "อาร์กิวเมนต์ 1 ที่ส่งผ่านไปยัง phpwtf () ต้องเป็นอินสแตนซ์ของ myClass, สตริงที่กำหนด"


3

อย่างที่คนอื่นพูดไปแล้วการแนะนำการพิมพ์ในขณะนี้ใช้ได้กับประเภทวัตถุเท่านั้น แต่ผมคิดว่าข้อผิดพลาดโดยเฉพาะอย่างยิ่งที่คุณอาจจะมีการหารือในการจัดทำประเภทสตริงที่จะเกิดขึ้นSplString

ในทางทฤษฎีมันจะทำงานเหมือนสตริง แต่เนื่องจากเป็นวัตถุที่จะผ่านการตรวจสอบประเภทวัตถุ น่าเสียดายที่ยังไม่ได้อยู่ใน PHP 5.3 อาจมาใน 5.4 ดังนั้นจึงยังไม่ได้ทดสอบ


2

ในฐานะของ PHP 7.0 ประเภทการประกาศอนุญาตให้มีชนิดเกลาดังนั้นประเภทนี้ที่มีตอนนี้: self, array, callable, bool, float, ,int stringสามตัวแรกมีอยู่ใน PHP 5 แต่สี่ตัวหลังเป็นของใหม่ใน PHP 7 หากคุณใช้สิ่งอื่น (เช่นintegerหรือboolean) ที่จะถูกตีความเป็นชื่อคลาส

ดูคู่มือ PHP สำหรับข้อมูลเพิ่มเติม


0

อาจไม่ปลอดภัยและสวย แต่ถ้าคุณต้อง:

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
ฉันยังสามารถสร้างnew string(array(1,2,3))
จิมมี่ต.

0

ฉันได้รับข้อผิดพลาดนี้เมื่อเรียกใช้ฟังก์ชั่นจาก Laravel Controller ไปยังไฟล์ PHP

หลังจากสองสามชั่วโมงฉันพบปัญหา: ฉันใช้$ นี้จากภายในฟังก์ชันคงที่


Using $this when not in object contextแท้จริงแล้วเป็นข้อความที่คลุมเครือ
Ben Fransen

0

(โพสต์สร้างสรรค์โดยleepowersในคำถามของเขา)

ข้อความแสดงข้อผิดพลาดทำให้เกิดความสับสนด้วยเหตุผลสำคัญหนึ่งข้อ:

ชื่อประเภทดั้งเดิมไม่ได้สงวนไว้ใน PHP

ต่อไปนี้คือการประกาศคลาสที่ถูกต้องทั้งหมด:

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

ความผิดพลาดของฉันคือการคิดว่าข้อความแสดงข้อผิดพลาดนั้นอ้างอิงถึงชนิดของสายอักขระดั้งเดิม - คำว่า 'อินสแตนซ์' ควรให้ฉันหยุดชั่วคราว ตัวอย่างเพื่ออธิบายเพิ่มเติม:

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')]);

เอาท์พุท:

$ s1 - สตริงดั้งเดิม? ใช่ - เช่นสตริง? ไม่

$ s2 - สตริงดั้งเดิม? ไม่ - เช่นสตริง? ใช่

ใน PHP มันเป็นไปได้สำหรับstringที่จะเป็นยกเว้นเมื่อมันเป็นจริงstring stringเช่นเดียวกับภาษาใด ๆ ที่ใช้การแปลงโดยนัยบริบทจะเป็นทุกอย่าง


-1

ฉันคิดว่า typecasting ใน php ใน block ภายใน String ใน PHP ไม่ได้เป็นวัตถุที่ฉันรู้:

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

2
คุณสามารถเพิ่มการตรวจสอบ is_string () ภายในฟังก์ชั่นของคุณเพื่อป้องกันไม่ให้ค่าอื่นผ่านไปยังฟังก์ชั่น
subosito

1
(string) $sอาจโยนข้อผิดพลาดหาก$sเป็นวัตถุที่ไม่สามารถทอดเป็นสตริง (ไม่มี__toString()วิธีการใช้งาน) ดังนั้นมันจึงไม่ง่ายอย่างนั้น
Yanick Rochon

ใช่ Yanick คุณพูดถูก แต่เราไม่สามารถบังคับให้อินพุตทั้งหมดเป็นสตริงได้ใช่ไหม นั่นเป็นสาเหตุที่ทำให้เกิดข้อยกเว้น เราสามารถรวมการตรวจสอบความถูกต้องเข้ากับข้อยกเว้นสำหรับส่วนที่เหลือ;)
subosito

ฉันแค่บอกว่าการหล่อตัวแปรให้เป็นสตริงโดยไม่ตรวจสอบก่อนว่าควรหลีกเลี่ยงตัวแปรที่ต้องส่งออกได้หรือไม่เนื่องจากการจับข้อยกเว้นนั้นมีค่าใช้จ่ายสูงและนำไปสู่รูปแบบการออกแบบที่ไม่ดี
Yanick Rochon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.