Kodokon kodokon.com

उन्नत PHP 8: एट्रिब्यूट, readonly, कॉलेबल

एट्रिब्यूट, readonly, फ़र्स्ट-क्लास कॉलेबल और PHP 8 के कठोर टाइपिंग की आंतरिक कार्यप्रणाली का अन्वेषण करें।

10 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

एट्रिब्यूट docblock एनोटेशन को असली क्लास से बदल देते हैं, जिन्हें इंजन सत्यापित करता है। एक एट्रिब्यूट निष्क्रिय मेटाडेटा के अलावा कुछ नहीं है: #[Route('/users')] लिखना कोई ऑब्जेक्ट नहीं बनाता। यह केवल तभी जीवंत होता है जब कोई कोड रिफ़्लेक्शन के माध्यम से इससे क्वेरी करता है और newInstance() को कॉल करता है - फ़्रेमवर्क अपनी रूटिंग तालिकाएँ बनाने के लिए स्टार्टअप पर ठीक यही करते हैं। अनुमत लक्ष्य (TARGET_METHOD, TARGET_CLASS...) को स्वयं एट्रिब्यूट क्लास पर एक एट्रिब्यूट द्वारा घोषित किया जाता है।

PHP
<?php
declare(strict_types=1);

#[Attribute(Attribute::TARGET_METHOD)]
final class Route
{
    public function __construct(
        public readonly string $path,
        public readonly string $method = 'GET'
    ) {}
}

final class UserController
{
    #[Route('/users', method: 'GET')]
    public function index(): array
    {
        return ['users' => []];
    }
}

$ref = new ReflectionMethod(
    UserController::class,
    'index'
);

foreach ($ref->getAttributes(Route::class) as $attr) {
    $route = $attr->newInstance();
    echo $route->method, ' ', $route->path, PHP_EOL;
}
एट्रिब्यूट केवल newInstance() के क्षण पर इंस्टैंशिएट किया जाता है।

readonly - 8.1 में प्रॉपर्टी, 8.2 में पूरी क्लास - गारंटी देता है कि किसी प्रॉपर्टी को क्लास के दायरे के भीतर से केवल एक बार लिखा जाता है। यह वैल्यू ऑब्जेक्ट के लिए उपकरण है: कोई भी "संशोधन" एक नए ऑब्जेक्ट का निर्माण बन जाता है, जो साझा-अवस्था वाले बग के एक पूरे परिवार को समाप्त कर देता है। एक readonly क्लास के लिए आवश्यक है कि इसकी सभी प्रॉपर्टी टाइप की हुई और नॉन-स्टैटिक हों।

PHP
<?php
declare(strict_types=1);

final readonly class Money
{
    public function __construct(
        public int $amount,
        public string $currency
    ) {}

    public function add(Money $other): self
    {
        if ($other->currency !== $this->currency) {
            throw new InvalidArgumentException(
                'Currency mismatch'
            );
        }
        return new self(
            $this->amount + $other->amount,
            $this->currency
        );
    }
}

$total = new Money(500, 'EUR');
$total = $total->add(new Money(250, 'EUR'));
echo $total->amount;
एक वैल्यू ऑब्जेक्ट: जोड़ना एक नया इंस्टैंस बनाता है।

फ़र्स्ट-क्लास कॉलेबल सिंटैक्स strtoupper(...) (PHP 8.1) किसी भी फ़ंक्शन या मेथड से एक Closure बनाता है। 'strtoupper' जैसी स्ट्रिंग या [$obj, 'method'] जैसे ऐरे के विपरीत, प्रतीक को निर्माण के समय सत्यापित किया जाता है और स्थैतिक विश्लेषण उपकरण टाइप को आरंभ से अंत तक अनुसरण करते हैं। किसी इंस्टैंस मेथड के लिए, क्लोज़र ऑब्जेक्ट को कैप्चर करता है; किसी स्टैटिक मेथड के लिए, केवल क्लास को।

PHP
<?php
declare(strict_types=1);

$words = ['php', 'rust', 'go'];

$upper = strtoupper(...);
var_dump($upper('php'));

print_r(array_map(strtoupper(...), $words));

final class Mailer
{
    public function send(string $to): bool
    {
        return $to !== '';
    }

    public static function ping(): string
    {
        return 'pong';
    }
}

$mailer = new Mailer();
$send = $mailer->send(...);
$ping = Mailer::ping(...);

var_dump($send('dev@example.org'), $ping());
हर f(...) व्यंजक एक Closure उत्पन्न करता है जो निर्माण के समय सत्यापित होता है।

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. किसी #[Route(...)] एट्रिब्यूट की क्लास कब इंस्टैंशिएट की जाती है?
    • जब इसे धारण करने वाली फ़ाइल संकलित होती है
    • जैसे ही सजाया गया मेथड कॉल किया जाता है
    • केवल तभी जब कोई कोड रिफ़्लेक्शन के माध्यम से इससे क्वेरी करता है और newInstance() को कॉल करता है
  2. एक readonly प्रॉपर्टी वास्तव में क्या गारंटी देती है?
    • जिस ऑब्जेक्ट को यह संदर्भित करती है वह पूर्णतः अपरिवर्तनीय हो जाता है
    • इसे केवल एक बार, क्लास के दायरे के भीतर से लिखा जाता है; संदर्भित ऑब्जेक्ट स्वयं परिवर्तनीय बना रहता है
    • इसे केवल उसी क्लास से पढ़ा जा सकता है जो इसे घोषित करती है
  3. declare(strict_types=1) का दायरा क्या है?
    • जैसे ही कोई एक फ़ाइल इसे घोषित करती है, पूरा प्रोजेक्ट
    • उस फ़ाइल में लिखी गई कॉल जिसमें घोषणा होती है
    • केवल उस फ़ाइल में परिभाषित फ़ंक्शन, चाहे उन्हें कहीं भी कॉल किया जाए