Κλάσεις και αντικειμενοστρέφεια

CLASS#

Επιστρέφει το όνομα της κλάσης του στιγμιότυπου που χειρίζεται τη δεδομένη στιγμή.

Το __CLASS__ είναι ένα διακριτικό που αναγνωρίζεται κατά τη μεταγλώττιση και αποτιμάται σε χρόνο εκτέλεσης στο όνομα της κλάσης του στιγμιότυπου που το επικαλείται. Μέσα σε σώμα method ή σε έκφραση αρχικοποιητή field (που εισάγεται με use feature 'class'), δίνει την πραγματική κλάση του αντικειμένου που κατασκευάζεται ή χρησιμοποιείται - η οποία μπορεί να είναι υποκλάση του πακέτου στο οποίο βρίσκεται κειμενικά ο κώδικας. Εκτός κώδικα που χρησιμοποιεί το χαρακτηριστικό class, είναι κατ” ουσίαν ισοδύναμο με το ref($self), όμως σε αντίθεση με το ref μπορεί να χρησιμοποιηθεί σε αρχικοποιητή πεδίου, όπου το $self δεν έχει ακόμη δεσμευτεί.

Σύνοψη#

use feature 'class';

field $x = __CLASS__->DEFAULT_X;        # in a field initializer
method m { return __CLASS__; }          # in a method body

Τι επιστρέφεται#

Μια απλή συμβολοσειρά: το όνομα της κλάσης του στιγμιότυπου που την επικαλείται. Η τιμή είναι το ίδιο είδος συμβολοσειράς που επιστρέφει η ref για μια blessed αναφορά. Δεν είναι αναφορά· καλέστε μεθόδους πάνω της όπως θα κάνατε για οποιοδήποτε όνομα κλάσης.

my $name = __CLASS__;                   # e.g. "DifferentCustomField"
my $obj  = __CLASS__->new(...);         # class-method dispatch

Πότε διαφέρει από το __PACKAGE__#

Το __PACKAGE__ επιλύεται κατά τη μεταγλώττιση και ονοματίζει το πακέτο στο οποίο εμφανίζεται κειμενικά το διακριτικό. Το __CLASS__ επιλύεται σε χρόνο εκτέλεσης και ονοματίζει την κλάση του στιγμιότυπου - η οποία, για μέθοδο ή αρχικοποιητή πεδίου που κληρονομείται από υποκλάση, είναι η υποκλάση.

use feature 'class';

class Base {
    field $f = __CLASS__->default_f;    # evaluated per instance
    sub default_f { 10 }
    method class_name { __CLASS__ }
    method pkg_name  { __PACKAGE__ }
}

class Derived :isa(Base) {
    sub default_f { 20 }
}

my $obj = Derived->new;
$obj->class_name;                       # "Derived"
$obj->pkg_name;                         # "Base"
# $f was initialised to 20, not 10, because __CLASS__ dispatched
# through the Derived package.

Σε μη κληρονομικό περιβάλλον (χωρίς υποκλάσεις), τα __CLASS__ και __PACKAGE__ αποδίδουν την ίδια συμβολοσειρά.

Παραδείγματα#

Μέθοδος κλάσης που καλείται από αρχικοποιητή πεδίου - η κανονική περίπτωση χρήσης. Χωρίς το __CLASS__, μια υποκλάση δεν μπορεί να υπερκαλύψει την προεπιλογή:

use feature 'class';

class WithCustomField {
    use constant DEFAULT_X => 10;
    field $x = __CLASS__->DEFAULT_X;
}

class DifferentCustomField :isa(WithCustomField) {
    sub DEFAULT_X { rand > 0.5 ? 20 : 30 }
}

my $obj = DifferentCustomField->new;    # $x is 20 or 30, not 10

Μέσα σε σώμα μεθόδου, ισοδύναμο με ref $self:

class Logger {
    method log ($msg) {
        print STDERR "[", __CLASS__, "] $msg\n";
    }
}

Κατασκευή νέου στιγμιότυπου της ίδιας κλάσης με το αντικείμενο που το επικαλείται - χρήσιμο για εργοστασιακές μεθόδους τύπου clone που πρέπει να σέβονται τις υποκλάσεις:

class Node {
    field $label :param;
    method spawn ($child_label) {
        return __CLASS__->new(label => $child_label);
    }
}

Σύγκριση με το __PACKAGE__ για διαγνωστικά που θέλουν να καρφώσουν τον ακριβή στόχο αποστολής:

class Thing {
    method describe {
        return sprintf "defined in %s, dispatched as %s",
            __PACKAGE__, __CLASS__;
    }
}

Οριακές περιπτώσεις#

  • Έγκυρο μόνο υπό use feature 'class' μέσα σε σώμα method, σε αρχικοποιητή field, ή σε άλλη κατασκευή του χαρακτηριστικού class (για παράδειγμα μπλοκ ADJUST). Η χρήση του εκτός τέτοιου περιβάλλοντος είναι σφάλμα κατά τη μεταγλώττιση.

  • Χωρίς παρενθέσεις, χωρίς ορίσματα. Το __CLASS__ είναι διακριτικό τύπου bareword, όχι κλήση συνάρτησης. Το __CLASS__() είναι συντακτικό σφάλμα.

  • Δεν είναι το ίδιο με ref $self κατά την αρχικοποίηση των πεδίων - το $self δεν έχει ακόμη δεσμευτεί όσο τα πεδία ορίζονται, άρα το ref $self δεν είναι διαθέσιμο. Το __CLASS__ είναι ο μόνος τρόπος να φτάσετε στην κλάση του στιγμιότυπου μέσα από αρχικοποιητή πεδίου.

  • Δεν είναι ref για κλήση μεθόδου κλάσης. Όταν καλείται ως μέθοδος κλάσης (χωρίς στιγμιότυπο στο χέρι), το __CLASS__ αποδίδει την κλάση πάνω στην οποία κλήθηκε η μέθοδος, όχι το πακέτο στο οποίο ορίστηκε η μέθοδος. Αυτό αντικατοπτρίζει την κανονική αποστολή μεθόδου.

  • Συμβολοσειρά, όχι αναφορά. Οι κλήσεις μεθόδων μέσω __CLASS__->... είναι αποστολές μεθόδων κλάσης, όχι αποστολές μεθόδων στιγμιότυπου. Η μέθοδος δεν θα δει blessed αναφορά ως invocant.

  • Το χαρακτηριστικό class είναι σημειωμένο ως πειραματικό στην Perl 5.42· εκπέμπει προειδοποίηση experimental::class εκτός αν σιγηθεί με no warnings 'experimental::class'.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • __PACKAGE__ - όνομα πακέτου κατά τη μεταγλώττιση του περιβάλλοντος κώδικα· χρησιμοποιήστε το όταν θέλετε το κειμενικό πακέτο, όχι την κλάση χρόνου εκτέλεσης

  • ref - όνομα κλάσης χρόνου εκτέλεσης μιας blessed αναφοράς· χρησιμοποιήστε το όταν κρατάτε ήδη στιγμιότυπο και δεν βρίσκεστε μέσα σε αρχικοποιητή πεδίου

  • bless - συσχετίζει μια αναφορά με όνομα κλάσης· η χαμηλού επιπέδου πρωτογενής λειτουργία στην οποία τελικά επιλύεται η αποστολή τύπου __CLASS__

  • isa - ελέγχει αν η τρέχουσα κλάση είναι υποκλάση ενός δοθέντος ονόματος· συνδυάζεται φυσικά με το __CLASS__ για ελέγχους χρόνου εκτέλεσης

  • sub - δηλώνει υπορουτίνες, συμπεριλαμβανομένης της μορφής method που κάνει το __CLASS__ να έχει νόημα