PHP 7 में गुणों के लिए संकेत टाइप करें?


80

क्या php 7 सपोर्ट टाइप क्लास प्रॉपर्टीज के लिए इशारा करता है?

मेरा मतलब है, बसने वाले / पाने वाले के लिए नहीं बल्कि संपत्ति के लिए ही।

कुछ इस तरह:

class Foo {
    /**
     *
     * @var Bar
     */
    public $bar : Bar;
}

$fooInstance = new Foo();
$fooInstance->bar = new NotBar(); //Error

1
यह नही है कि मैं जानता हूँ। हालांकि, आम तौर पर किसी संपत्ति के मूल्य पर किसी भी बाधा को बोलते हुए एक सेटर के माध्यम से वैसे भी किया जाना चाहिए। चूंकि सेटर आसानी से "मान" तर्क के लिए एक प्रकार का प्रकार हो सकता है, आप जाने के लिए अच्छे हैं।
नीट द डार्क एबसोल

कई रूपरेखाएँ संरक्षित विशेषताओं (ज्यादातर नियंत्रकों के लिए) का उपयोग करती हैं। विशेष रूप से उन मामलों के लिए यह बहुत उपयोगी होगा।
कार्लोसकारुस

जवाबों:


134

PHP 7.4 टाइप की गई संपत्तियों का समर्थन करेगा :

class Person
{
    public string $name;
    public DateTimeImmutable $dateOfBirth;
}

PHP 7.3 और पहले इसका समर्थन नहीं करते हैं, लेकिन कुछ विकल्प हैं।

आप एक निजी संपत्ति बना सकते हैं जो केवल गेटर्स और सेटरों के माध्यम से सुलभ है जिनके पास घोषणाएं हैं:

class Person
{
    private $name;
    public function getName(): string {
        return $this->name;
    }
    public function setName(string $newName) {
        $this->name = $newName;
    }
}

आप एक सार्वजनिक संपत्ति भी बना सकते हैं और एक डॉकब्लॉक का उपयोग करके कोड पढ़ने और आईडीई का उपयोग करने वाले लोगों को प्रकार की जानकारी प्रदान कर सकते हैं, लेकिन यह कोई रनटाइम टाइप-चेकिंग प्रदान नहीं करता है:

class Person
{
    /**
      * @var string
      */
    public $name;
}

और वास्तव में, आप गेटर्स और सेटर्स और एक डॉकब्लॉक को जोड़ सकते हैं।

आप अधिक साहसिक कर रहे हैं, आप के साथ एक नकली संपत्ति कर सकता है __get, __set, __issetऔर __unsetजादू के तरीकों , और प्रकार अपने आप की जाँच करें। मुझे यकीन नहीं है कि मैं इसे सुझाऊँगा, हालाँकि।


वास्तव में अच्छा लगता है। अगले रिलीज पर आने वाले व्हाट्सएप को देखने के लिए इंतजार नहीं कर सकता!
कार्लोसकारुस

एक अन्य महत्वपूर्ण मुद्दा संदर्भों से निपटने का है, जो वास्तव में प्रकार की घोषणाओं के साथ अच्छी तरह से बातचीत नहीं करते हैं और ऐसी संपत्तियों के लिए अक्षम होना पड़ सकता है। प्रदर्शन के मुद्दों के बिना भी, करने में सक्षम नहीं है, कहते हैं, array_push($this->foo, $bar)या sort($this->foobar)एक बड़ी बात होगी।
एंड्रिया

प्रकार के काम का जोर कैसे होगा? उदाहरण के लिए: (new Person())->dateOfBirth = '2001-01-01';... बशर्ते declare(strict_types=0);कि है। क्या यह DateTimeImmutableकंस्ट्रक्टर को फेंक देगा या इस्तेमाल करेगा ? और अगर यह मामला है, तो स्ट्रिंग को अमान्य दिनांक होने पर किस तरह की त्रुटि डाली जाएगी? TypeError?
लमेरिनो

@ इमेरिनो डेटाइम (अपरिवर्तनीय) के लिए कोई निहित रूपांतरण नहीं है और कभी भी नहीं किया गया है
एंड्रिया

12

7.4+:

अच्छी खबर है कि इसे नए रिलीज में लागू किया जाएगा, जैसा कि @Andrea ने बताया। मैं इस समाधान को यहाँ छोड़ दूंगा अगर कोई इसे 7.4 से पहले उपयोग करना चाहता है


7.3 या उससे कम है

इस थ्रेड से मुझे प्राप्त होने वाली सूचनाओं के आधार पर, मेरा मानना ​​है कि वहाँ से बाहर कई लोगों के पास / मेरे पास एक ही मुद्दा है। इस मामले के लिए मेरा समाधान इस व्यवहार को अनुकरण करने के लिए एक विशेषता के अंदर वास + __setजादू विधि का संयोजन था । यह रहा:

trait SettersTrait
{
    /**
     * @param $name
     * @param $value
     */
    public function __set($name, $value)
    {
        $setter = 'set'.$name;
        if (method_exists($this, $setter)) {
            $this->$setter($value);
        } else {
            $this->$name = $value;
        }
    }
}

और यहाँ प्रदर्शन है:

class Bar {}
class NotBar {}

class Foo
{
    use SettersTrait; //It could be implemented within this class but I used it as a trait for more flexibility

    /**
     *
     * @var Bar
     */
    private $bar;

    /**
     * @param Bar $bar
     */
    protected function setBar(Bar $bar)
    {
        //(optional) Protected so it wont be called directly by external 'entities'
        $this->bar = $bar;
    }
}

$foo = new Foo();
$foo->bar = new NotBar(); //Error
//$foo->bar = new Bar(); //Success

व्याख्या

सबसे पहले, barएक निजी संपत्ति के रूप में परिभाषित करें ताकि PHP __set स्वचालित रूप से डाली जाएगी ।

__setजाँच करेगा कि क्या वर्तमान वस्तु ( method_exists($this, $setter)) में कुछ सेटर घोषित है । अन्यथा यह केवल इसका मूल्य निर्धारित करेगा जैसा कि सामान्य रूप से होता है।

एक सेट्टर विधि (सेटबार) घोषित करें जो एक प्रकार-संकेतित तर्क ( setBar(Bar $bar)) प्राप्त करता है ।

जब तक PHP यह पता लगा लेती है कि कुछ ऐसा नहीं है जो इंस्टेंटBar को पास नहीं किया जा रहा है, तो यह ऑटोमैटिकली एक फाल्ट एरर को ट्रिगर करेगा: अनकैप टाइप टाइप: Argument 1 को Foo :: passBar () में पास करना बार का उदाहरण होना चाहिए, NotBar का उदाहरण।


4

PHP 7.4 के लिए संपादित करें:

PHP 7.4 के बाद से आप विशेषताएँ ( डॉक्यूमेंटेशन / विकी ) टाइप कर सकते हैं जिसका अर्थ है कि आप कर सकते हैं:

    class Foo
{
    protected ?Bar $bar;
    public int $id;
    ...
}

विकि के अनुसार, सभी स्वीकार्य मूल्य हैं:

  • बूल, इंट, फ्लोट, स्ट्रिंग, एरे, ऑब्जेक्ट
  • चलने योग्य
  • स्व, माता-पिता
  • किसी भी वर्ग या इंटरफ़ेस का नाम
  • प्रकार? // जहां "प्रकार" उपरोक्त में से कोई भी हो सकता है

PHP <7.4

यह वास्तव में संभव नहीं है और आपके पास वास्तव में अनुकरण करने के लिए केवल 4 तरीके हैं:

  • डिफ़ॉल्ट मान
  • टिप्पणी ब्लॉक में सज्जाकार
  • कंस्ट्रक्टर में डिफ़ॉल्ट मान
  • गेटएटर और सेटर

मैंने उन सभी को यहाँ जोड़ा

class Foo
{
    /**
     * @var Bar
     */
    protected $bar = null;

    /** 
    * Foo constructor
    * @param Bar $bar
    **/
    public function __construct(Bar $bar = null){
        $this->bar = $bar;
    }
    
    /**
    * @return Bar
    */
    public function getBar() : ?Bar{
        return $this->bar;
    }

    /**
    * @param Bar $bar
    */
    public function setBar(Bar $bar) {
        $this->bar = $bar;
    }
}

ध्यान दें कि आप वास्तव में रिटर्न को टाइप कर सकते हैं? Php 7.1 के बाद से बार (अशक्त) क्योंकि यह शून्य हो सकता है (php7.0 में उपलब्ध नहीं)।

आप php7.1 से शून्य के रूप में रिटर्न भी टाइप कर सकते हैं


1

आप सेटर का उपयोग कर सकते हैं

class Bar {
    public $val;
}

class Foo {
    /**
     *
     * @var Bar
     */
    private $bar;

    /**
     * @return Bar
     */
    public function getBar()
    {
        return $this->bar;
    }

    /**
     * @param Bar $bar
     */
    public function setBar(Bar $bar)
    {
        $this->bar = $bar;
    }

}

$fooInstance = new Foo();
// $fooInstance->bar = new NotBar(); //Error
$fooInstance->setBar($fooInstance);

आउटपुट:

TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of Foo given, called in ...
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.