dal 2015 - visita n. 1462
php objects parte 3
php objects parte 3

 

Modificatori del controllo di accesso

Esistono delle parole chiave speciali che è possibile inserire prima di una classe, di una definizione di funzione di classe, o di una variabile di classe per modificare il modo in cui PHP lavora con esse: Ecco l'elenco completo con la descrizione sintetica per ognuna di esse:

Dopo queste descrizioni sommarie, però, è meglio verificare il tutto con degli esempi.


public

Le variabili e le funzioni public sono accessibili da qualsiasi punto dello script, il che rende questo modificatore il più facile da utilizzare. Ai tempi di PHP 4, tutte le variabili oggetto venivano dichiarate con "var" ed erano essenzialmente public, ma oggi questa metodica è deprecata perchè può generare avvisi warning da parte del compilatore. Esaminiamo il codice seguente:

<?php
    class dog {
        public $Name;

        public function bark() {
            print "Woof!\n";
        }
    }

    class poodle extends dog {
        public function bark() {
            print "Yip!\n";
        }
    }

    $poppy = new poodle;
    $poppy->Name = "Poppy";
    print $poppy->Name;
?> 

Possiamo provarlo così com'è oppure omettendo la parola chiave public, il funzionamento sarà lo stesso in entrambi i casi. La ragione è che, per impostazione predefinita, tutte le funzioni di classe sono public, e prima di PHP 5 non c'era altra possibilità.

Benchè la parola chiave public non sia necessaria, è consigliabile utilizzarla comunque. E' un buon modo per ricordare alle persone che leggono il codice che una determinata funzione è davvero pubblica, ed anche perchè potrebbe succedere che le funzioni di classe, senza un modificatore di accesso, possano essere deprecate in futuro.

E' sempre necessario specificare un modificatore di accesso per le variabili, perché altrimenti non ci sarebbe modo di definire quali variabili ha una classe. Le versioni precedenti di PHP usavano la parola chiave "var" per dichiarare le variabili di classe, ma perché non era ancora stato introdotto il modificatore di accesso, adesso si dovrebbe evitare questa modalità e specificare sempre una delle parole chiave: public, private, ...


private

Il problema con l'impostazione public è che si permette che le funzioni possano essere chiamate da tutti e che le variabili possano essere impostate da qualsiasi punto dello script, il che in genere non è una cosa molto furba. In precedenza abbiamo definito un oggetto $DogTag di classe dogtag all'interno di ogni oggetto di classe cane così come la variabile $Name.
Se avessimo cambiato la variabile $Name, si sarebbe aggiornato automaticamente anche $DogTag ? Naturalmente no, e sarebbe rimasto lo stesso, ma diverso dal nuovo valore $Name:

$poppy = new poodle;
$poppy->Name = "Poppy";
$poppy->DogTag = new dogtag;
$poppy->DogTag->Words = "Mi chiamo Poppy. Se mi trovi, chiama il 567.1234";
$poppy->Name = "Penny";
print $poppy->DogTag->Words; 

Se si prova ad eseguire, si vedrà qual'è il problema. Questo dipende dal fatto che abbiamo permesso che da qualsiasi parte dello script si possa accedere direttamente alla struttura interna degli oggetti cane. Ecco una possibile soluzione:

class dog {
    public $Name;
    public $DogTag;

    public function setName($NewName) {
        $Name = $NewName;
        $DogTag->Words = "Mi chiamo $NewName. Se mi trovi, chiama il 567.1234";
    } 

Questa volta l'oggetto cane ha incorporata la logica che gli permette di rinominare correttamente l'output del messaggio. Ogni volta che si usa la funzione setName() vengono aggiornati correttamente sia il nome del cane sia la sua targhetta.

Tuttavia nello script precedente è ancora possibile creare dei problemi o per disattenzione o per deliberata volontà, per esempio scrivendo qualcosa del tipo:

$poppy->Name = "Rover"; 

anzichè usare, come previsto, la speciale funzione setName(). A questo punto entrano in azione le variabili private, dichiarando la variabile $Name private questa potrà essere cambiata soltanto dall'interno della sua classe. Ecco allora il nuovo codice:

class dog {
    private $Name;
    private $DogTag;

    public function setName($NewName) {

Da notare che sono state dichiarate private sia $Name sia $DogTag, il che significa che nessuno potrà usarle direttamente dall'esterno, ma soltanto tramite la funzione setName(), rimasta invece public per consentire a tutti di poterla utilizzare.

Adesso, se il nostro programmatore distratto tenterà di impostare $Name direttamente, utilizzando un codice tipo $poppy->Name, non otterrà più il risultato che si aspetta.Se si cerca, infatti, di modificare direttamente una variabile private PHP emette automaticamente un messaggio di errore. Però, se tale variabile privata è stata ereditata da un'altra classe, PHP cercherà di sistemare le cose disponendo di una variabile privata e una di una variabile pubblica. Questo potrebbe creare un po' di confusione, ma il codice seguente dovrebbe chiarire la situazione:

<?php
    class dog {
        private $Name;
    }

    class poodle extends dog { }

    $poppy = new poodle;
    $poppy->Name = "Poppy";
    print_r($poppy);
?> 

Eseguendo questo script si otterrà:

poodle Object
(
[Name:private] =>
[Name] => Poppy
)

Si noti che ci sono due variabili Name, una che è private e non può essere toccata, e un'altra che PHP crea per uso locale, come richiesto. Chiaramente questa situazione è confusa, e si dovrebbe cercare di evitarla, se possible.

Nota che le funzioni e le variabili private sono accessibili esclusivamente dalla classe che le possiede. Le classi figlie non possono accedere alle variabili ed alle funzioni private dei genitori. Per poterlo fare è necessaria, invece, la parola chiave protected.


protected

Le variabili e le funzioni contrassegnate come protected sono accessibili solo attraverso l'oggetto che le possiede, che siano o non siano dichiarate nella classe dell'oggetto, anche se sono derivate da una classe genitore. Si consideri il seguente codice:

<?php
    class dog {
        public $Name;
        private function getName() {
            return $this->Name;
        }
    }

    class poodle extends dog {
        public function bark() {
            print "'Woof', says " . $this->getName();
        }
    }
    
    $poppy = new poodle;
    $poppy->Name = "Poppy";
    $poppy->bark();
?> 

In questo codice, la classe poodle è una estensione della classe dog, la classe dog ha una variabile public $Name ed una funzione private getName(), e la classe poodle ha una funzione public chiamata bark(). Quindi, creiamo un poodle, diamo il valore "Poppy" alla sua variabile $Name (la variabile $Name deriva dalla classe dog), poi chiediamo l'esecuzione di bark(). La funzione bark() è public, il che significa che la possiamo chiamare come indicato sopra,la qual cosa sembra perfettamente corretta.

Si noti tuttavia che la funzione bark() chiama la funzione getName(), che fa parte della classe dog e che è stata contrassegnata come private, questo fermerà il lavoro dello script, perché le variabili e le funzioni private non sono accessibili dalle classi ereditate. Cioè, non possiamo accedere alle funzioni ed alle variabili private di dog dall'interno della classe poodle.

Ora proviamo a cambiare bark() in protected, e tutto dovrebbe diventare chiaro, la variabile rimane ancora non disponibile per il mondo intero, ma gestisce l'eredità come ci si aspetta, il che significa che possiamo accedere a getName() da dentro poodle.


final

La parola chiave final viene usata per dichiarare che una funzione o classe non possono essere sovrascritte da una sottoclasse. Questo è un altro modo per impedire ad altri utilizzatori di usare il codice di fuori dei limiti che sono stati previsti. Diamo un'occhiata al seguente codice:

class dog {
    private $Name;
    private $DogTag;
    final public function bark() {
        print "Woof!\n";
    }

La funzione bark() di dog viene ora dichiarata come final, il che significa che non può essere sovrascritta in una classe figlia. Se si ridefinisce bark() nella classe poodle, PHP emette un messaggio di errore fatale: Cannot override final method dog::bark(). L'uso della parola chiave final è assolutamente facoltativo, ma rende la vita più facile, in quanto agisce da salvaguardia contro la sovracsrittura di una funzione che si vuole sia definitiva.

Per una maggiore protezione, la parola chiave final può anche essere utilizzata per dichiarare una classe come uninheritable, cioè dalla quale non è possibile estendere altre classi. Diamo un'occhiata a questo script:

<?php
    final class dog {
        public $Name;
        private function getName() {
            return $this->Name;
        }
    }

    class poodle extends dog {
        public function bark() {
            print "'Woof', says " . $this->getName();
        }
    }
?> 

Appena si tenta di eseguire questo script si otterrà un messaggio di errore fatale: Class poodle may not inherit from final class (dog).


abstract

La parola chiave abstract viene usata per affermare che una funzione o una classe non possono essere create nel programma. Questo sembrerebbe un non senso, in un primo momento. Infatti, perché preoccuparsi di definire una classe per poi dire che nessuno la può utilizzare? Beh, è utile perché non impedisce al programmatore di ereditare da quella classe astratta per crearne una nuova, questa volta non-abstract, (vera). Consideriamo questo codice:

$poppy = new dog; 

Questo codice è perfettamente legale, abbiamo una classe dog, e stiamo creando una istanza di questa assegnandola a $poppy. Tuttavia, poichè sappiamo che cataloghiamo i cani secondo delle razze reali, che senso ha un codice che crea un cane senza nessuna razza particolare ? Poichè riteniamo che anche i cani meticci debbano essere catalogati secondo una razza non dobbiamo consentire che questo sia possibile nel nostro modello.

La parola chiave abstract ci può aiutare in questo caso, ecco un esempio di codice:

abstract class dog {
    private $Name;
// etc

$poppy = new dog;  

La classe dog adesso viene dichiarata abstract e $poppy viene creato come un oggetto dog astratto. Con il risultato che PHP ferma l'esecuzione con un errore fatale: Cannot instantiate abstract class dog.

Come già detto, è possibile utilizzare la parola chiave abstract anche con le funzioni, ma se una classe ha almeno una funzione astratta la classe stessa deve essere dichiarata astratta. Inoltre, si otterranno degli errori se si tenta di inserire qualsiasi codice all'interno di una funzione astratta: Il codice seguente non è corretto:

abstract class dog {
    abstract function bark() {
        print "Woof!";
    }
}

Anche questo codice non è corretto:

abstract class dog {
    abstract function bark() { }
}

Invece una funzione astratta corretta assomiglierà a questa:

abstract class dog {
    abstract function bark();
}

Se può servire a capire meglio, si può pensare alle classi astratte come se fossero simili a delle interfacce, come vedremo tra breve.


















Menù
Introduzione
Ambiente di sviluppo
intro php-01
tag e commenti php-02
variabili e tipi php-03
operatori php-04
php IF esercizi
php FOR esercizi
php objects intro
php objects parte 1
php objects parte 2
php objects parte 3
php objects parte 4
php objects parte 5
CLIL
php socket intro
php socket parte 1
php socket parte 2
php socket parte 3
php socket parte 4
php socket parte 5
php socket parte 6
php socket extra
linux netcat


MiniGuida PHP
Guida Ufficiale PHP (en)
Form Base
Flat DataBase
Pagine Protette
mySQL



La via del saggio è agire, ma non competere.
Lao Tzu

Valid CSS!
pagina generata in 0.004 secondi