PHPDoc บอกใบ้ถึงอาร์เรย์ของวัตถุหรือไม่?


417

ดังนั้นใน PHPDoc หนึ่งสามารถระบุ@varข้างต้นประกาศตัวแปรสมาชิกเพื่อแบะท่าประเภทของมัน จากนั้น IDE สำหรับอดีต PHPEd จะรู้ว่ามันทำงานกับวัตถุประเภทใดและจะสามารถให้ข้อมูลเชิงลึกเกี่ยวกับโค้ดสำหรับตัวแปรนั้นได้

<?php
  class Test
  {
    /** @var SomeObj */
    private $someObjInstance;
  }
?>

วิธีนี้ใช้งานได้ดีจนกระทั่งฉันต้องทำสิ่งเดียวกันกับอาร์เรย์ของวัตถุเพื่อให้ได้คำใบ้ที่เหมาะสมเมื่อฉันวนซ้ำวัตถุเหล่านั้นในภายหลัง

ดังนั้นมีวิธีประกาศแท็ก PHPDoc เพื่อระบุว่าตัวแปรสมาชิกเป็นอาร์เรย์ของSomeObj? @varอาร์เรย์ไม่เพียงพอและ@var array(SomeObj)ดูเหมือนจะไม่ถูกต้องเช่น


2
มีการอ้างอิงในบล็อก Netbeans 6.8 dev นี้ซึ่ง IDE นั้นฉลาดพอที่จะอนุมานประเภทสมาชิกอาเรย์: blogs.sun.com/netbeansphp/entry/php_templates_improved
John Carter

3
@therefromhere: ลิงก์ของคุณเสีย ฉันคิดว่า URL ใหม่คือ: blogs.oracle.com/netbeansphp/entry/php_templates_improved
DanielaWaranie

สำหรับคนอย่างฉันผ่านและค้นหาคำตอบ: ถ้าคุณใช้ PHPS รูปแบบให้ดูคำตอบที่โหวตมากที่สุด: มันมีคำใบ้เฉพาะ! stackoverflow.com/a/1763425/1356098 (นี่ไม่ได้หมายความว่ามันควรจะเป็นคำตอบสำหรับ OP เนื่องจากเขาขอ PHPEd เป็นตัวอย่าง)
Erenor Paz

คำตอบ:


337

ใช้:

/* @var $objs Test[] */
foreach ($objs as $obj) {
    // Typehinting will occur after typing $obj->
}

เมื่อพิมพ์การอินไลน์ตัวแปรและ

class A {
    /** @var Test[] */
    private $items;
}

สำหรับคุณสมบัติคลาส

คำตอบก่อนหน้าจาก '09 เมื่อ PHPDoc (และ IDEs เช่น Zend Studio และ Netbeans) ไม่มีตัวเลือก:

สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือพูดว่า

foreach ($Objs as $Obj)
{
    /* @var $Obj Test */
    // You should be able to get hinting after the preceding line if you type $Obj->
}

ฉันทำสิ่งนั้นมากในสตูดิโอ Zend ไม่ทราบเกี่ยวกับบรรณาธิการอื่น ๆ แต่มันควรจะทำงาน


3
มันสมเหตุสมผล แต่มันใช้งานไม่ได้กับ PHPEd 5.2 สิ่งเดียวที่ฉันสามารถทำให้เกิดขึ้นได้ก็คือ foreach ($ Objs เป็น / ** @var Test * / $ Obj) ซึ่งน่าเกลียดอย่างน่ากลัว :(
Artem Russakovskii

14
หมายเหตุใน Netbeans 7 ดูเหมือนว่าจะมีความสำคัญที่คุณมีเครื่องหมายดอกจันเพียงอันเดียว - /** @var $Obj Test */ใช้งานไม่ได้
ควบคุม

3
@contrebis: "@var" เป็นแท็ก docblock ที่ถูกต้อง ดังนั้นแม้ว่า IDE ของคุณไม่รองรับภายใน docblock "/ ** ... /" และรองรับ "@var" ใน "/ ... * /" เท่านั้น - โปรดโปรดอย่าเปลี่ยน docblock ที่ถูกต้อง ยื่นปัญหาไปยังตัวติดตามบั๊กของ IDE ของคุณเพื่อให้ IDE ของคุณสอดคล้องกับมาตรฐาน ลองนึกภาพทีมพัฒนา / นักพัฒนาภายนอก / ชุมชนใช้ IDE ที่แตกต่างกัน ให้มันเป็นและเตรียมไว้สำหรับอนาคต
DanielaWaranie

181
ทำให้แน่ใจว่าคุณดูด้านล่าง! ฉันเกือบจะไม่เลื่อนลง - คงจะเป็นความผิดพลาดครั้งใหญ่ !!! IDEs จำนวนมากจะสนับสนุนไวยากรณ์ที่ดีกว่า! (คำใบ้: @var Object[] $objectsบอกว่า "$ objects" เป็นอาร์เรย์ของอินสแตนซ์ของ Object)
Thom Porter

10
/** @var TYPE $variable_name */เป็นไวยากรณ์ที่ถูกต้อง; อย่าย้อนกลับลำดับของประเภทและชื่อตัวแปร (ตามที่แนะนำไว้ก่อนหน้านี้ในความคิดเห็น) เนื่องจากมันจะไม่ทำงานในทุกกรณี
srcspider

893

ใน PhpStorm IDE จาก JetBrains คุณสามารถใช้/** @var SomeObj[] */เช่น:

/**
 * @return SomeObj[]
 */
function getSomeObjects() {...}

เอกสาร PHPDocแนะนำวิธีการนี้:

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

ตัวอย่าง: @return int[]


10
ฉันเพิ่งดาวน์โหลดและใช้ phpstorm ในสัปดาห์ที่ผ่านมา เอาชนะ heck out of Aptana (ซึ่งยอดเยี่ยมสำหรับการเป็นอิสระ) นี่คือสิ่งที่ฉันกำลังมองหา จริงๆแล้วมันเป็นแบบเดียวกับที่คุณทำเพื่อ JavaScript ฉันควรเดา
Juan Mendes

3
ขอบคุณคน! นี่คือสิ่งที่ฉันกำลังมองหา PHPS รูปแบบเป็นเลิศ
Erik Schierboom

5
สิ่งนี้ใช้ไม่ได้กับ Netbeans ฉันผิดหวัง Jetbrains สร้างเครื่องมือที่ดีมาก
Keyo

10
@fishbone @Keyo งานนี้ใน Netbeans ตอนนี้ (ใน 7.1 ทุกคืนอย่างน้อยอาจจะเร็วกว่านี้) แม้ว่ามันจะดูเหมือนว่าคุณจำเป็นต้องใช้ตัวแปรชั่วคราว (บั๊ก?) คำใบ้สำหรับforeach(getSomeObjects() as $obj)ใช้งานไม่ได้ แต่ทำเพื่อ$objs = getSomeObjects(); foreach($objs as $obj)
John Carter

2
คงจะดีถ้ามี@var Obj[string]อาร์เรย์ที่เชื่อมโยงกัน
donquixote

59

คำแนะนำ Netbeans:

คุณจะได้รับโค้ดที่สมบูรณ์ใน$users[0]->และสำหรับ$this->อาร์เรย์ของคลาสผู้ใช้

/**
 * @var User[]
 */
var $users = array();

คุณยังสามารถดูประเภทของอาร์เรย์ในรายการสมาชิกคลาสเมื่อคุณทำเสร็จ $this->...


4
ทำงานใน PhpStorm 9 EAP เช่นกัน: / ** * @var UserInterface [] * / var $ users = []; // Array of Objs ใช้งานอินเทอร์เฟซ
Ronan

ฉันได้ลองใช้ใน NetBeans IDE 8.0.2 แล้ว แต่ฉันได้รับคำแนะนำจากชั้นเรียนที่ฉันกำลังเรียนอยู่
Wojciech Jasiński

นอกจากนี้ยังทำงานใน Eclipse 4.6.3 (IDK สิ่งสนับสนุนรุ่นได้รับการแนะนำให้รู้จัก แต่การทำงานของตนและสิ่งที่ผมใช้ตอนนี้)
hanshenrik

น่าเสียดายที่นี่ใช้งานไม่ได้หลังจากใช้งานarray_pop()หรือฟังก์ชั่นที่คล้ายกันด้วยเหตุผลบางประการ ดูเหมือนว่า Netbeans จะไม่รับรู้ถึงฟังก์ชั่นเหล่านั้นคืนองค์ประกอบเดียวของอาร์เรย์อินพุต
William W

29

ในการระบุตัวแปรคืออาร์เรย์ของวัตถุ:

$needles = getAllNeedles();
/* @var $needles Needle[] */
$needles[1]->...                        //codehinting works

ใช้งานได้กับ Netbeans 7.2 (ฉันใช้อยู่)

ใช้ได้กับ:

$needles = getAllNeedles();
/* @var $needles Needle[] */
foreach ($needles as $needle) {
    $needle->...                        //codehinting works
}

ดังนั้นการใช้การประกาศภายในforeachไม่จำเป็น


2
โซลูชันนี้สะอาดกว่าคำตอบที่ยอมรับในมุมมองของฉันเพราะคุณสามารถใช้งานได้หลายครั้งและคำใบ้ประเภทจะยังคงใช้งาน/* @var $Obj Test */คำอธิบายประกอบใหม่ต่อไปทุกครั้ง
Henry

ฉันเห็นปัญหาสองข้อที่นี่: 1. phpdoc ที่เหมาะสมเริ่มต้นด้วย/** 2.รูปแบบที่ถูกต้องคือ@var <data-type> <variable-name>
Christian

@ คริสเตียน 1: คำถามหลักไม่ใช่ phpdoc แต่การพิมพ์ 2: รูปแบบที่ถูกต้องไม่เหมือนที่คุณพูดแม้แต่ตามคำตอบอื่น ๆ ในความเป็นจริงฉันเห็น 2 ประเด็นกับความคิดเห็นของคุณและฉันสงสัยว่าทำไมคุณถึงได้ให้คำตอบของคุณเองด้วยรูปแบบที่ถูกต้อง
Highmastdon

1. การพิมพ์ดีดทำงานกับ phpdoc ... หากคุณไม่ใช้ docblock IDE ของคุณจะไม่ลองเดาสิ่งที่คุณเขียนในความคิดเห็นแบบสุ่ม 2.รูปแบบที่ถูกต้องเช่นเดียวกับคำตอบอื่น ๆ ก็คือสิ่งที่ฉันระบุไว้ข้างต้น ชนิดข้อมูลก่อนชื่อตัวแปร 3.ฉันไม่ได้เขียนคำตอบอื่นเพราะคำถามไม่ต้องการคำตอบอื่นและฉันไม่ต้องการเพียงแค่แก้ไขรหัสของคุณ
คริสเตียน

24

PSR-5: PHPDocเสนอรูปแบบของสัญกรณ์สไตล์ Generics

วากยสัมพันธ์

Type[]
Type<Type>
Type<Type[, Type]...>
Type<Type[|Type]...>

ค่าในคอลเล็กชันอาจเป็นอีกชุดหนึ่งและอาจเป็นชุดรวมก็ได้

Type<Type<Type>>
Type<Type<Type[, Type]...>>
Type<Type<Type[|Type]...>>

ตัวอย่าง

<?php

$x = [new Name()];
/* @var $x Name[] */

$y = new Collection([new Name()]);
/* @var $y Collection<Name> */

$a = new Collection(); 
$a[] = new Model_User(); 
$a->resetChanges(); 
$a[0]->name = "George"; 
$a->echoChanges();
/* @var $a Collection<Model_User> */

หมายเหตุ: หากคุณคาดหวังว่า IDE จะทำการช่วยเหลือโค้ดมันเป็นคำถามอีกข้อหนึ่งที่เกี่ยวกับว่า IDE รองรับรูปแบบคอลเลกชัน PHPDoc Generic หรือไม่

จากคำตอบของฉันคำถามนี้


สัญกรณ์ทั่วไปถูกลบออกจาก PSR-5
zored

11

ฉันชอบอ่านและเขียนโค้ดสะอาด - ตามที่ระบุไว้ใน "Clean Code" โดย Robert C. Martin เมื่อติดตามลัทธิความเชื่อของเขาคุณไม่ควรกำหนดให้นักพัฒนา (ในฐานะผู้ใช้ API ของคุณ) รู้โครงสร้าง (ภายใน) ของอาร์เรย์ของคุณ

ผู้ใช้ API อาจถาม: นั่นคืออาร์เรย์ที่มีหนึ่งมิติเท่านั้นหรือไม่ วัตถุแพร่กระจายไปรอบ ๆ ในทุกระดับของอาเรย์หลายมิติหรือไม่? ฉันต้องมีลูปซ้อนกันกี่วง (foreach และอื่น ๆ ) ในการเข้าถึงวัตถุทั้งหมดหรือไม่ วัตถุประเภทใดที่ "เก็บไว้" ในอาเรย์นั้น?

ตามที่คุณระบุไว้คุณต้องการใช้อาร์เรย์นั้น (ซึ่งมีวัตถุ) เป็นอาร์เรย์หนึ่งมิติ

ตามที่ Nishi ระบุไว้คุณสามารถใช้:

/**
 * @return SomeObj[]
 */

สำหรับการที่.

แต่อีกครั้ง: ระวัง - นี่ไม่ใช่เครื่องหมาย docblock มาตรฐาน สัญกรณ์นี้ถูกนำเสนอโดยผู้ผลิต IDE บางราย

ตกลงโอเคในฐานะนักพัฒนาที่คุณรู้ว่า "[]" เชื่อมโยงกับอาร์เรย์ใน PHP แต่ "บางอย่าง []" หมายถึงอะไรในบริบทของ PHP ปกติ? "[]" หมายถึง: สร้างองค์ประกอบใหม่ภายใน "บางสิ่ง" องค์ประกอบใหม่อาจเป็นทุกอย่าง แต่สิ่งที่คุณต้องการแสดงคืออาร์เรย์ของวัตถุที่มีประเภทเดียวกันและเป็นประเภทที่แน่นอน อย่างที่คุณเห็นผู้สร้าง IDE แนะนำบริบทใหม่ บริบทใหม่ที่คุณต้องเรียนรู้ บริบทใหม่ที่นักพัฒนา PHP คนอื่นต้องเรียนรู้ (เพื่อทำความเข้าใจ docblock ของคุณ) สไตล์ไม่ดี (!)

เนื่องจากอาเรย์ของคุณมีหนึ่งมิติคุณอาจต้องการเรียกว่า "อาเรย์ของวัตถุ" รายการ " โปรดระวังว่า "รายการ" มีความหมายพิเศษมากในภาษาการเขียนโปรแกรมอื่น มันจะดีกว่าที่จะเรียกว่า "คอลเลกชัน" ตัวอย่างเช่น

เตือนความจำ: คุณใช้ภาษาการเขียนโปรแกรมที่ช่วยให้คุณมีตัวเลือกทั้งหมดของ OOP ใช้คลาสแทนอาเรย์และทำให้คลาสของคุณ traversable เหมือนอาเรย์ เช่น:

class orderCollection implements ArrayIterator

หรือถ้าคุณต้องการจัดเก็บวัตถุภายในในระดับที่แตกต่างกันภายในโครงสร้างอาร์เรย์ / วัตถุหลายมิติ:

class orderCollection implements RecursiveArrayIterator

วิธีนี้จะแทนที่อาเรย์ของคุณด้วยวัตถุประเภท "orderCollection" แต่อย่าเปิดใช้งานการเติมโค้ดให้สมบูรณ์ภายใน IDE ของคุณ ตกลง. ขั้นตอนต่อไป:

ใช้วิธีการที่นำมาใช้โดยส่วนต่อประสานกับ docblock โดยเฉพาะ:

/**
 * [...]
 * @return Order
 */
orderCollection::current()

/**
 * [...]
 * @return integer E.g. database identifier of the order
 */
orderCollection::key()

/**
 * [...]
 * @return Order
 */
orderCollection::offsetGet()

อย่าลืมใช้การบอกกล่าวแบบสำหรับ:

orderCollection::append(Order $order)
orderCollection::offsetSet(Order $order)

วิธีนี้จะหยุดการแนะนำจำนวนมาก:

/** @var $key ... */
/** @var $value ... */

ทั่วทุกไฟล์รหัสของคุณ (เช่นภายในลูป) ตามที่ Zahymaka ยืนยันด้วยคำตอบของเขา / เธอ ผู้ใช้ API ของคุณไม่ได้ถูกบังคับให้แนะนำ docblock นั้นเพื่อให้ได้รหัสที่สมบูรณ์ หากต้องการให้ @return อยู่ในที่เดียวจะช่วยลดความซ้ำซ้อน (@var) เป็น mutch ให้มากที่สุด การโรย "docBlocks ด้วย @var" จะทำให้โค้ดของคุณอ่านง่ายที่สุด

สุดท้ายคุณเสร็จแล้ว ดูยากที่จะเข้าใจ ดูเหมือนว่าจะเอาค้อนขนาดใหญ่มาทุบแคร็กไหม? ไม่ใช่เรื่องจริงเนื่องจากคุณคุ้นเคยกับอินเทอร์เฟซนั้นและรหัสที่สะอาด ข้อควรจำ: ซอร์สโค้ดของคุณเขียนครั้งเดียว / อ่านหลายครั้ง

หากการทำให้โค้ดของ IDE ของคุณไม่ทำงานด้วยวิธีการนี้ให้เปลี่ยนไปใช้วิธีที่ดีกว่า (เช่น IntelliJ IDEA, PhpStorm, Netbeans) หรือยื่นคำขอคุณสมบัติในตัวติดตามปัญหาของผู้ผลิต IDE ของคุณ

ขอบคุณ Christian Weiss (จากเยอรมัน) ที่ได้เป็นครูฝึกของฉันและสอนฉันอย่างยอดเยี่ยม PS: พบกับฉันและเขาใน XING


ดูเหมือนว่า "ถูกต้อง" แต่ฉันไม่สามารถทำงานกับ Netbeans ได้ ทำตัวอย่างเล็ก ๆ น้อย ๆ : imgur.com/fJ9Qsro
fehrlich

2
อาจในปี 2012 นี้เป็น "ไม่ได้มาตรฐาน" แต่ตอนนี้มันถูกอธิบายว่าเป็นฟังก์ชั่นในตัวของ phpDoc
Wirone

@Wirone ดูเหมือนว่า phpDocumentor เพิ่มสิ่งนี้ลงในคู่มือของมันเพื่อตอบสนองต่อผู้ผลิต IDE แม้ว่าคุณจะมีเครื่องมือรองรับที่หลากหลาย แต่ก็ไม่ได้หมายความว่าเป็นแนวปฏิบัติที่ดีที่สุด มันเริ่มที่จะรับ SomeObj [] แพร่กระจายในโครงการมากขึ้นคล้ายกับต้องการ, require_once, รวมและ include_once ทำเมื่อหลายปีก่อน ด้วยการโหลดอัตโนมัติลักษณะที่ปรากฏของข้อความนั้นลดลงต่ำกว่า 5% หวังว่า SomeObj [] จะลดลงสู่อัตราเดิมภายใน 2 ปีข้างหน้าเนื่องจากแนวทางข้างต้น
DanielaWaranie

1
ฉันไม่เข้าใจว่าทำไม นี่เป็นสัญกรณ์ที่ง่ายและชัดเจน เมื่อคุณเห็นSomeObj[]คุณรู้ว่ามันเป็นSomeObjอินสแตนซ์สองมิติของอินสแตนซ์แล้วคุณรู้ว่าจะทำอย่างไรกับมัน ฉันไม่คิดว่ามันจะไม่เป็นไปตาม credo "clean code"
Wirone

นี่ควรเป็นคำตอบ ไม่ใช่วิธีการสนับสนุน IDE ทั้งหมดที่มี@return <className>สำหรับcurrent()และทุกคน PhpStorm รองรับดังนั้นมันช่วยฉันได้มาก ขอบคุณเพื่อน!
Pavel

5

ใช้array[type]ในสตูดิโอ Zend

ใน Zend สตูดิโอ, array[MyClass]หรือarray[int]หรือแม้กระทั่งการarray[array[MyClass]]ที่ดีในการทำงาน


5

ใน NetBeans 7.0 (อาจต่ำกว่านี้ด้วย) คุณสามารถประกาศประเภทการคืนค่า "อาเรย์กับออบเจกต์ Text" ได้เช่นเดียวกับที่@return Textการบอกรหัสจะทำงาน:

แก้ไข:อัปเดตตัวอย่างด้วยคำแนะนำ @Bob Fanger

/**
 * get all Tests
 *
 * @return Test|Array $tests
 */
public function getAllTexts(){
    return array(new Test(), new Test());
}

และเพียงแค่ใช้มัน:

$tests =  $controller->getAllTests();
//$tests->         //codehinting works!
//$tests[0]->      //codehinting works!

foreach($tests as $text){
    //$test->      //codehinting works!
}

มันไม่สมบูรณ์แบบ แต่มันจะดีกว่าถ้าจะปล่อยให้มันแค่ "มิกซ์" ซึ่งไม่มีค่าอะไรเลย

CONS เป็นคุณได้รับอนุญาตให้เหยียบอาร์เรย์เป็นวัตถุข้อความซึ่งจะทำให้เกิดข้อผิดพลาด


1
ฉันใช้ "@return array | ทดสอบคำอธิบายบางอย่าง" ซึ่งก่อให้เกิดพฤติกรรมเดียวกัน แต่อธิบายเพิ่มเติมเล็กน้อย
Bob Fanger

1
นี่เป็นวิธีแก้ปัญหาไม่ใช่วิธีแก้ปัญหา สิ่งที่คุณกำลังพูดอยู่ที่นี่คือ "ฟังก์ชั่นนี้อาจส่งคืนวัตถุประเภท 'ทดสอบ' หรืออาร์เรย์" ในทางเทคนิคแล้วมันไม่ได้บอกอะไรคุณเกี่ยวกับสิ่งที่อาจจะอยู่ในอาร์เรย์
Byson

5

ดังที่ DanielaWaranie พูดถึงในคำตอบของเธอ - มีวิธีการระบุประเภทของ $ item เมื่อคุณวนซ้ำ $ items ใน $ collectionObject: เพิ่ม@return MyEntitiesClassNameไปยังcurrent()ส่วนที่เหลือของIteratorและArrayAccess-methods ที่ส่งคืนค่า

บูม! ไม่จำเป็นต้องอยู่ใน/** @var SomeObj[] $collectionObj */มากกว่าforeachและการทำงานที่เหมาะสมกับวัตถุคอลเลกชัน, @return SomeObj[]คอลเลกชันจำเป็นที่จะต้องกลับมาด้วยวิธีการเฉพาะไม่มีการอธิบายว่า

ฉันสงสัยว่าไม่สนับสนุน IDE ทั้งหมด แต่ทำงานได้อย่างสมบูรณ์ใน PhpStorm ซึ่งทำให้ฉันมีความสุขมากขึ้น

ตัวอย่าง:

class MyCollection implements Countable, Iterator, ArrayAccess {

    /**
     * @return User
     */
    public function current() {
        return $this->items[$this->cursor];
    }

    //... implement rest of the required `interface` methods and your custom
}

มีประโยชน์อะไรฉันจะเพิ่มการโพสต์คำตอบนี้

ในกรณีของฉันcurrent()และส่วนที่เหลือของ - interfaceวิธีการที่จะดำเนินการในAbstractชั้นเรียนการเก็บรวบรวมและฉันไม่ทราบว่าหน่วยงานประเภทใดจะถูกเก็บไว้ในคอลเลกชันในที่สุด

ดังนั้นนี่คือเคล็ดลับ: อย่าระบุประเภทการส่งคืนในคลาสนามธรรมแทนใช้ PhpDoc instuction @methodในคำอธิบายของคลาสคอลเลกชันเฉพาะ

ตัวอย่าง:

class User {

    function printLogin() {
        echo $this->login;
    }

}

abstract class MyCollection implements Countable, Iterator, ArrayAccess {

    protected $items = [];

    public function current() {
        return $this->items[$this->cursor];
    }

    //... implement rest of the required `interface` methods and your custom
    //... abstract methods which will be shared among child-classes
}

/**
 * @method User current()
 * ...rest of methods (for ArrayAccess) if needed
 */
class UserCollection extends MyCollection {

    function add(User $user) {
        $this->items[] = $user;
    }

    // User collection specific methods...

}

ตอนนี้การใช้คลาส:

$collection = new UserCollection();
$collection->add(new User(1));
$collection->add(new User(2));
$collection->add(new User(3));

foreach ($collection as $user) {
    // IDE should `recognize` method `printLogin()` here!
    $user->printLogin();
}

อีกครั้ง: ฉันสงสัยว่าไม่สนับสนุน IDE ทั้งหมด แต่ PhpStorm ทำ ลองของคุณโพสต์ในความคิดเห็นผลลัพธ์!


คูปองสำหรับการผลักดันมันไปไกล แต่โชคร้ายที่ฉันยังสามารถแก้ไขตัวเองให้มีความเชี่ยวชาญคอลเลกชันที่จะมาแทนที่จาวาเก่าดีประเภททั่วไป .... yuck'
Sebas

ขอบคุณ. คุณจะพิมพ์วิธีคงที่ได้อย่างไร
Yevgeniy Afanasyev

3

ฉันรู้ว่าฉันมางานปาร์ตี้ช้า แต่ตอนนี้ฉันกำลังแก้ไขปัญหานี้อยู่ ฉันหวังว่าบางคนเห็นสิ่งนี้เพราะคำตอบที่ยอมรับแม้ว่าถูกต้องไม่ใช่วิธีที่ดีที่สุดที่คุณสามารถทำได้ ไม่ได้อยู่ใน PHPS รูปแบบอย่างน้อยฉันยังไม่ได้ทดสอบ NetBeans

วิธีที่ดีที่สุดเกี่ยวข้องกับการขยายคลาส ArrayIterator แทนที่จะใช้ชนิดอาร์เรย์เนทิฟ สิ่งนี้ช่วยให้คุณพิมพ์คำใบ้ในระดับคลาสแทนที่จะเป็นอินสแตนซ์ระดับซึ่งหมายความว่าคุณต้องใช้ PHPDoc เพียงครั้งเดียวไม่ใช่ตลอดรหัสของคุณ (ซึ่งไม่เพียง แต่ยุ่งและละเมิด DRY เท่านั้น แต่ยังเป็นปัญหาเมื่อพูดถึง refactoring - PHPStorm มีนิสัยที่ขาดหายไปของ PHPDoc เมื่อทำการเปลี่ยนโครงสร้างใหม่)

ดูรหัสด้านล่าง:

class MyObj
{
    private $val;
    public function __construct($val) { $this->val = $val; }
    public function getter() { return $this->val; }
}

/**
 * @method MyObj current()
 */
class MyObjCollection extends ArrayIterator
{
    public function __construct(Array $array = [])
    {
        foreach($array as $object)
        {
            if(!is_a($object, MyObj::class))
            {
                throw new Exception('Invalid object passed to ' . __METHOD__ . ', expected type ' . MyObj::class);
            }
        }
        parent::__construct($array);
    }

    public function echoContents()
    {
        foreach($this as $key => $myObj)
        {
            echo $key . ': ' . $myObj->getter() . '<br>';
        }
    }
}

$myObjCollection = new MyObjCollection([
    new MyObj(1),
    new MyObj('foo'),
    new MyObj('blah'),
    new MyObj(23),
    new MyObj(array())
]);

$myObjCollection->echoContents();

กุญแจสำคัญในที่นี้คือ PHPDoc @method MyObj current()แทนที่ประเภทผลตอบแทนที่สืบทอดมาจาก ArrayIterator (ซึ่งก็คือmixed) การรวม PHPDoc นี้หมายความว่าเมื่อเราทำซ้ำมากกว่าคุณสมบัติของคลาสที่ใช้foreach($this as $myObj)เราจะได้รับโค้ดที่สมบูรณ์เมื่ออ้างถึงตัวแปร$myObj->...

สำหรับฉันนี่เป็นวิธีที่เรียบร้อยที่สุดในการบรรลุเป้าหมายนี้ (อย่างน้อยก็จนกว่า PHP จะแนะนำ Typed Arrays ถ้าพวกเขาทำ) เนื่องจากเราประกาศประเภทตัววนซ้ำในคลาส iterable ไม่ใช่คลาสที่กระจัดกระจายไปทั่วโค้ด

ฉันยังไม่ได้แสดงโซลูชันที่สมบูรณ์สำหรับการขยาย ArrayIterator ดังนั้นหากคุณใช้เทคนิคนี้คุณอาจต้องการ:

  • รวม PHPDoc ระดับชั้นอื่นตามต้องการสำหรับวิธีการเช่นoffsetGet($index)และnext()
  • ย้ายการตรวจสอบสติis_a($object, MyObj::class)จากผู้สร้างไปยังวิธีการส่วนตัว
  • เรียกใช้การตรวจสอบสติ (ตอนนี้ส่วนตัว) จากการแทนที่เมธอดเช่นoffsetSet($index, $newval)และappend($value)

ทางออกที่ดีและสะอาดมาก! :)
Marko Šutija

2

ปัญหาคือว่า @varสามารถแสดงประเภทเดียว - ไม่มีสูตรที่ซับซ้อน หากคุณมีไวยากรณ์สำหรับ "array of Foo" ทำไมหยุดที่นั่นและไม่เพิ่มไวยากรณ์สำหรับ "array of array ที่มี 2 Foo และสาม Bar" ฉันเข้าใจว่ารายการองค์ประกอบอาจทั่วไปมากกว่านั้น แต่มันเป็นทางลาดลื่น

โดยส่วนตัวฉันมีบางครั้งที่ใช้@var Foo[]เพื่อระบุ "อาร์เรย์ของ Foo" แต่ก็ไม่ได้รับการสนับสนุนจาก IDE


5
หนึ่งในสิ่งที่ฉันชอบเกี่ยวกับ C / C ++ คือว่ามันจะคอยติดตามประเภทต่างๆจนถึงระดับนี้ นั่นเป็นความชันที่น่ายินดีมากที่จะล้มลง
Brilliand

2
ได้รับการสนับสนุนโดย Netbeans 7.2 (อย่างน้อยนั่นคือการใช้งานที่ผมรุ่น) แต่มี ajustment เล็ก ๆ น้อย ๆ /* @var $foo Foo[] */คือ: เพิ่งเขียนคำตอบด้านล่างเกี่ยวกับมัน สามารถใช้ในforeach(){}ลูปได้
Highmastdon

1
<?php foreach($this->models as /** @var Model_Object_WheelModel */ $model): ?>
    <?php
    // Type hinting now works:
    $model->getImage();
    ?>
<?php endforeach; ?>

5
IDE แบบใดที่สนับสนุนสิ่งนี้
philfreo

21
มันน่าเกลียดมาก บอกลารหัสสะอาดเมื่อคุณเริ่มโปรแกรมเช่นนี้
halfpastfour.am

ลองดูที่คำตอบของฉันด้วยการกำหนดเนื้อหาของอาร์เรย์: stackoverflow.com/a/14110784/431967
Highmastdon

-5

ฉันพบบางสิ่งที่ใช้งานได้มันสามารถช่วยชีวิตคนได้!

private $userList = array();
$userList = User::fetchAll(); // now $userList is an array of User objects
foreach ($userList as $user) {
   $user instanceof User;
   echo $user->getName();
}

11
ปัญหาเดียวก็คือแนะนำรหัสเพิ่มเติมที่จะดำเนินการซึ่ง IDE ของคุณใช้อย่างหมดจดเท่านั้น จะดีกว่ามากในการกำหนดประเภทคำใบ้ภายในความคิดเห็นแทน
Ben Rowe

1
ว้าวนี้ใช้งานได้ดี คุณจะท้ายด้วยรหัสเพิ่มเติม แต่ดูเหมือนว่าจะไม่เป็นอันตราย ฉันจะเริ่มทำ: $ x instanceof Y; // typehint
Igor Nadj

3
เปลี่ยนเป็น IDE ที่ให้โค้ดเสร็จสมบูรณ์ตาม docblocks หรือการตรวจสอบ หากคุณไม่ต้องการสลับไฟล์ IDE ของคุณคำขอคุณสมบัติในตัวติดตามปัญหาของ IDE ของคุณ
DanielaWaranie

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