Διαδρομές
/
PHP
PHP
/
Ύλη
/
Συμμεταβλητότητα και αντιμεταβλητότητα
Συ

Συμμεταβλητότητα και αντιμεταβλητότητα σε PHP

{one: "1 άσκηση", other: "%{count} ασκήσεις"}

Σχετικά με την έννοια Συμμεταβλητότητα και αντιμεταβλητότητα

Συνδιακύμανση και αντιδιακύμανση

Όταν χρησιμοποιείς τύπους ένωσης, πρέπει να γνωρίζεις τις έννοιες της συνδιακύμανσης και της αντιδιακύμανσης. Αυτές εξηγούνται στην τεκμηρίωση, αλλά αυτά τα παραδείγματα μπορεί να βοηθήσουν.

Ας υποθέσουμε ότι έχουμε μια κλάση Calculator που χρησιμοποιεί μια συνάρτηση όπως στο παραπάνω παράδειγμα:

class Calculator
{
    public function add(int|float $x, int|float $y): int|float
    {
        return $x + $y;
    }
}

Αν επεκτείνεις την κλάση, σου επιτρέπεται να αλλάξεις τους τύπους των παραμέτρων και τους τύπους επιστροφής, αλλά μόνο σύμφωνα με τους παρακάτω κανόνες.

Πρώτα, οι τύποι των παραμέτρων μπορούν να είναι "ευρύτεροι", δηλαδή να δέχονται περισσότερους τύπους από την βασική κλάση. Για παράδειγμα, αυτό επιτρέπεται:

class StringCalc extends Foo
{
    public function add(float|int|string $x, float|int|string $y): int|float
    {
        if (!is_numeric($x) || !is_numeric($y)) {
            throw new \InvalidArgumentException('$x and $y must be numeric');
        }
        return $x + $y;
    }
}

Θα μπορούσαμε να βάλουμε το StringCalc στη θέση του αρχικού Calculator και όλα θα λειτουργούσαν ακόμα. Ο κώδικας που καλεί θα μπορούσε ακόμα να στείλει float ή int, όπως μπορούσε αρχικά, και ο τύπος επιστροφής θα παρέμενε ο αναμενόμενος int ή float.

Παρομοίως, μπορείς να περιορίσεις τον τύπο επιστροφής, δηλαδή να τον κάνεις πιο συγκεκριμένο αφαιρώντας τύπους από την ένωση. Αυτό το παράδειγμα αξιοποιεί αυτόν τον κανόνα:

class IntCalc extends Calculator
{
    public function add(float|int $x, float|int $y) : int
    {
        return (int)($x + $y);
    }
}

Εφόσον το IntCalc δέχεται ακόμα int και float, μπορεί ακόμα να αντικαταστήσει ένα αρχικό Calculator χωρίς προβλήματα.

Για να διαβάσεις περισσότερα σχετικά με το τι επιτρέπεται και τι όχι, μπορείς να ανατρέξεις στην αρχή αντικατάστασης του Liskov (LSP).

Για ένα παράδειγμα του τι δεν θα επιτρεπόταν, ρίξε μια ματιά στο InvalidCalc παρακάτω:

class InvalidCalc extends Calculator
{
    public function add(int $x, int $y) : int|float|string
    {
        // Declaration must be compatible with Calculator->add(x: float|int, y: float|int)

        // Return type declaration must be compatible with Calculator->add(x: float|int, y: float|int) : float|int
    }
}

Η κλάση InvalidCalc δεν θα μεταγλωττιστεί και έχει δύο προβλήματα. Περιορίζοντας το τι επιτρέπεται ως παράμετρος, το InvalidCalc δεν θα μπορούσε να αντικαταστήσει το αρχικό Calculator, επειδή δεν δέχεται πλέον float. Επιπλέον, τώρα θα μπορούσε να επιστρέψει string, κάτι που επίσης δεν συγκαταλέγεται στους επιτρεπόμενους τύπους επιστροφής της αρχικής κλάσης.

Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα