PHP Lezione Itermedia – Oggetti Classi Proprietà Metodi Istanze Costruttori Distrutturi Ereditarietà Visibilità Overriding

Concetti intermedi nella programmazione ad oggetti in PHP

Let’s go on!

Creare Oggetti in PHP – Proprietà Dinamiche e Metodi Dinamici

Prima di tutto è necessario capire come funziona la programmazione ad oggetti in PHP.

Un oggetto è del codice che raccoglie delle variabili e le funzioni per processarle.

L’oggetto va dichiarato esplicitamente con la sintassi ‘class’.

Nel gergo della programmazione ad oggetti per essere precisi varibili e funzioni all’interno della classe sono indicati con una terminologia particolare, per essere più precisi:

– le variabili sono definiti proprietà o membri
– le funzioni sono definite metodi

La distinzione di nome è molto importante perchè mentre le normali variabili e funzioni sono componenti libere o di primo livello, le proprietà ed i metodi di una classe appartengono esclusivamente a questa classe (ed eventualmente alle classe che ereditano, come vedremo nelle successive lezioni).

Per richiamare e utilizzare una classe si usano le istanze o oggetti che vengono dichiarate con la sitassi ‘new’ ad esempio.

File1:


class MyClass { // dichiaro l'oggetto
 
        // variabili membro o meglio proprietà
        public $a = 10;
        public $b = 20;
         
        // funzioni o meglio metodi
        public function sayHello() {
                echo "Hello!";
        }
 
}

File2:


// DEVO dichiarare l'istanza, istanza cioè una copia di MyClass
$myClass_1 = new MyClass();
 
// richiama MyClass ed avvia la funzione sayHello() - stampa "Hello!"
$myClass_1->sayHello();
 
// richiama MyClass e preleva la variabile a - stampa 10
echo $myClass_1->a;

Per ogni classe può essere istanziato un numero illimitato di oggetti, ed inviare parametri:


$myClass_2 = new MyClass();
 
// ora la proprietà "a" dell'oggetto $myClass_2 è impostata a 20
$myClass_2->a = 20; // invia un valore ad a
 
// stampa 10
echo $myClass_1->a;

L’oggetto può essere dichiarato con le parentesi se vogliamo usare un costruttore pubblico nella classe
o senza le parentesi se non vogliamo usare un costruttore pubblico nella classe, in questo caso non abbiamo modo di influire sui parametri della classe.


$myClass_1 = new MyClass();
$myClass_2 = new MyClass;

Per richiamare valori variabili dall’interno della classe utilizzeremo la keyword $this che si riferisce sempre all’istanza corrente che stiamo utilizzando, o meglio al valore che è stato inviato dall’istanza.


class MyClass {
 
        // variabili membro o proprietà
        public $a = 10;
        public $b = 20;
         
        // funzioni o metodi
        public function sayHello() {
                echo "Hello! " . $this->a . " " . $this->b;
        }
 
}
 
$myClass_1 = new MyClass();
$myClass_2 = new MyClass();

// stampa "Hello! 10 20", usa i valori indicati all'interno della classe perchè l'istanza non ha inviato nulla
$myClass_1->sayHello();
 
// ora la proprietà "a" dell'oggetto $myClass_2 è impostata a 20
$myClass_2->a = 20;
 
// stampa "Hello! 20 20" perchè usa $this->a cioè il valore 'a' che proviene dall'istanza
$myClass_2->sayHello()

I metodi di una classe riconoscono TUTTE le keyword appartenenti alla classe.

Costruttori

Possiamo decidere quale comportamento deve assumere l’oggetto quando viene creato utilizzando il metoto costruttore o metodo magico con la sintassi __construct (doppio underscore e construct)


class MyClass {
 
        // proprietà
        public $a = 10;
        public $b = 20;
         
        // costruttore o metodo magico
        public function __construct($a, $b) {
                $this->a = $a;
                $this->b = $b;
        }
         
        // metodi
        public function sayHello() {
                echo "Hello! " . $this->a . " " . $this->b;
        }
 
}
 
// creazione delle istanze, notare che i parametri verranno passati al costruttore
$myClass_1 = new MyClass(40, 40);
$myClass_2 = new MyClass("a", "b");

Il funzionamento è il seguente:
1. $myClass_1 = new MyClass(40, 40); è una istanza che invoca MyClass() ed invia 40,10
2. MyClass riceve in public function __construct($a, $b)
3. Che assegna il valore alla variabile in base al valore ricevuto dall’istanza $this->a = $a;
4. sayHello() scrive Hello 40 40

Ovviamente in questo caso, non possiamo omettere i parametri nella fase di creazione delle istanze, altrimenti PHP genererebbe un E_WARNING che ci avvisa della mancata presenza dei parametri richiesti dal costruttore.

Controlli sui Costruttori

Sarà possibile inserire dei controlli alla variabili inviate dall’istanza ad esempio:


class MyClass {
 
        // proprietà
        public $a = 10;
        public $b = 20;
         
        // costruttore
        public function __construct($a, $b) {
                // gli argomenti devono essere interi
                if(!is_int($a) || !is_int($b)) exit("The arguments must be integers!");
                // gli argomenti devono essere minori di 100
                if($a > 100 || $b > 100) exit("The arguments must be less than 100!");
                 
                $this->a = $a;
                $this->b = $b;
                 
                // connessione ad un nostro dataase interno
                connect_to_my_db($this->a, $this->b);
                 
                // operazioni...
        }
         
        // metodi ...
 
}
 
// creazione delle istanze
$myClass_1 = new MyClass(40, 80);               // ok
$myClass_2 = new MyClass("a", "b");             // errore: "The arguments must be integers!"

NOTARE:
if(!is_int($a) || !is_int($b)) exit(“The arguments must be integers!”);
if($a > 100 || $b > 100) exit(“The arguments must be less than 100!”);

Distruttori

Per distruggere gli oggetti si utilizza il metodo magico __destruct (doppio underscore destruct), il metodo __destruct NON ACCETTA argomenti.

Il metodo distruttore viene utilizzato per il clean up delle risorse, ad esempio per la chiusura del database.


class MyClass {
 
        // proprietà
        public $a = 10;
        public $b = 20;
         
        // costruttore
        public function __construct($a, $b) {
                $this->a = $a;
                $this->b = $b;
                 
        }
         
        // distruttore
        public function __destruct() {
                echo "__destruct method called!";
        }
 
}
 
// creazione delle istanze
$myClass_1 = new MyClass("username", "password");
$myClass_2 = new MyClass("username", "password");
$myClass_3 = new MyClass("username", "password");
$myClass_4 = $myClass_3;
 
// distruzione delle istanze
unset($myClass_1);              // stampa "__destruct method called"
$myClass_2 = 0;                 // stampa "__destruct method called"
 
unset($myClass_3);              // non chiama il distruttore, esiste ancora un riferimento all'oggetto $myClass_3

PHP chiama il metodo distruttore solo quando è davvero sicuro che tutti i riferimenti all’oggetto siano stati cancellati oppure quando l’oggetto è distrutto/cancellato manualmente con unset.
Inoltre tutti gli oggetti, come del resto tutte le variabili, vengono distrutti automaticamente da PHP al termine dello script.

Uso di __destruct per la chiusura del database:


class MyClass {
 
        // proprietà
        public $a = 10;
        public $b = 20;
         
        // costruttore
        public function __construct($a, $b) {
                $this->a = $a;
                $this->b = $b;
                 
                // connessione al database interno
                connect_to_my_db($this->a, $this->b);
        }
         
        // distruttore
        public function __destruct() {
                // operazioni di clean up...
                // chiusura del database e rilascio delle risorse
                free_my_db();
        }
         
        // metodi
        public function sayHello() {
                echo "Hello! " . $this->a . " " . $this->b;
        }
 
}
 
// creazione delle istanze
$myClass_1 = new MyClass("username", "password");

Proprietà Statiche

Le proprietà statiche si dichiarano attraverso la parola chiave (“static”)

Le proprietà statiche non appartengono a nessuna istanza in particolare, quindi non possono essere richiamate con l’operatore di deferenziamento (“->”)

Sono di fatto componenti statiche di proprietà della classe stessa e vengono richiamate con l’operatore di risoluzione (“::”) oppure con la keyword self.


class MyClass {
 
        // proprietà statiche
        public static $apples = 10;
        public static $pineapples = 20;
 
}
 
// stampa 10
echo MyClass::$apples;
 
// stampa 20
echo MyClass::$pineapples;

Le proprietà statiche possono cambiare il loro valore:


class MyClass {
 
        // proprietà statiche
        public static $instances = 0;
        public $idKey = false;
         
        // costruttore
        public function __construct() {
                $this->idKey = ++self::$instances;
                echo "This is the #" . $this->idKey 
		. " instance of the class MyClass.Instances created: " . $this->idKey;
        }
         
        // distruttore
        public function __destruct() {
                echo "Instance #" . $this->idKey . " deleted.";
        }
 
}
 
// stampa "This is the #1 instance of the class MyClass. Instances created: 1"
$myClass_1 = new MyClass();
 
// stampa "This is the #2 instance of the class MyClass. Instances created: 2"
$myClass_2 = new MyClass();
 
// stampa "This is the #3 instance of the class MyClass. Instances created: 3"
$myClass_3 = new MyClass();
 
// al termine dello script: "Instance #1 deleted.", "Instance #2 deleted.", "Instance #3 deleted."

Metodi Statici

I metodi statici sono dati di classe che non appartengono a nessuna istanza in particolare. Anch’essi devono essere preceduti dalla keyword ‘static’ e richiamati con ::


class MyClass {
 
        // metodi statici
        public static function sayHello() {
                echo "Hello!";
        }
         
        public static function sayHelloAgain() {
                self::sayHello(); // la sintassi è self:: per richiamare il metodo statico dall'interno della classe
                echo " Again!";
        }
 
}
 
// stampa "Hello!"
MyClass::sayHello();
 
// stampa "Hello! Again!"
MyClass::sayHelloAgain();

Eredietarietà

Tramite l’ereditarietà (inheritance), una classe (sottoclasse o classe figlia), può ereditare sia i metodi che le proprietà da un’altra classe (superclasse o classe padre). Per estendere una classe si utilizza la keyword ‘extends’


class MyClass {
 
        const A = 10;
         
        // proprietà
        public $a = 10;
         
        // metodi
        public function sayHello() {
                echo "Hello!";
        }
 
}
 
class AnotherClass extends MyClass {
         
        // proprietà
        public $b = 10;
 
}
 
$myClass = new MyClass();
 
// stampa (10)
echo $myClass->a;
 
// modifica
$myClass->a = 20;
 
// chiamata ("Hello!")
$myClass->sayHello();
 
$anotherClass = new AnotherClass();
 
// stampa (10)
$anotherClass->a; // notare che non è stata influenzata dalla modifica =20
 
// chiamata ("Hello!")
$anotherClass->sayHello();

Public Protected Private

Tramite l’utilizzo delle keyword – public – protected – private – (indicatori di visibilità) possiamo definire la visibilità delle proprietà e dei metodi di una classe, in particolare

public
– interno della classe stessa: accessibile/modificabile
– esterno della classe: accessibile/modificabile
– interno classe che la ereditano (extends): accessibile/modificabile

protected
– interno della classe stessa: accessibile/modificabile
– esterno della classe: non accessibile (Fatal Error)
– interno classe che la ereditano (extends): accessibile/modificabile

private
– interno della classe stessa: accessibile/modificabile
– esterno della classe: non accessibile (Fatal Error)
– interno classe che la ereditano (extends): non accessibile


class MyClass {
         
        // proprietà
        protected $a = 10;
         
        // metodi
        protected function sayHello() {
                echo "Hello!";
        }
 
}
 
class AnotherClass extends MyClass {
 
        public function sayHelloAgain() {
                $this->sayHello();
        }
 
}
 
$anotherClass = new AnotherClass();
 
// stampa "Hello!"
$anotherClass->sayHelloAgain();

//  Fatal Error
echo $myClass->a;
 
// Fatal Error
$myClass->sayHello();

// Fatal error
$anotherClass->sayHello();

// Fatal Error
$anotherClass->sayHelloAgain();

Overriding o Ridefinizione

Con l’Overriding o ridefinizione estendiamo una classe al fine di sovrascrivere il vecchio metodo con uno nuovo:


class A {
        public function sayHello() {
                echo "Hello!";        
        }
}
 
class B extends A {
        public function sayHello() {
                echo "Ciao Ciao!";    
        }
}
 
$b = new B();
 
// stampa "Ciao Ciao!"
$b->sayHello(); // il metodo con lo stesso nome più nuovo prende il posto di quello vecchio.

Overriding – parent –

Utilizzando la keyword – parent:: – possiamo sommare il risultato di due metodi con lo stesso nome


class A {
 
        public function sayHello() {
                echo "Hello!";        
        }
 
}
 
class B extends A {
 
        public function sayHello() {
                parent::sayHello();
                echo "Ciao Ciao!";    
        }
 
}
 
$b = new B();
 
// stampa "Hello! Ciao Ciao!"
$b->sayHello(); // il risultato è la somma dei due metodi

Un esempio di parent sul costruttore


class A {
        public function __construct($a, $b, $c, $d) {
                $this->a = $a;
                $this->b = $b;
                $this->c = $c;
                $this->d = $d;
        }
         
        // metodi...
 
}
 
class B extends A {
        public function __construct($a, $b, $c, $d, $e) {
                parent::__construct($a, $b, $c, $d);
                $this->e = $e;
        }
         
        // metodi...
 
}
 
$b = new B(10, 20, 30, 40, 50);
 
echo $b->a;  // stampa 10
echo $b->b;  // stampa 20
echo $b->c;  // stampa 30
echo $b->d;  // stampa 40
echo $b->e;  // stampa 50

Come funziona?
1. Creo un’istanza basata sulla classe B ‘$b = new B(10, 20, 30, 40, 50);’ ed inviando dei valori
2. ‘class B extends A’ invoca il costruttore della classe padre ‘parent::__construct($a, $b, $c, $d);’
3. La classe parent assegna con il suo costruttore i valori ricevuti alle variabili ‘function __construct($a, $b, $c, $d){$this->a = $a;’
4. echo visualizza i valori delle variabili

Impedire Overriding di Metodi e Classi – final –

Per garantire stabilità alle nostre gerarchie si può impedire l’Overridind dei metodì crucialiper il funzionamento della nostra applicazione.
Ad esempio potremo impedire la ridefinizione della classe per il collegamento al database o il parsing dei documenti.
Per fare questo utilizzaremo la keyword – final –

Per i metodi:


class MyClass {
        final public function connect_to_my_db() {
                // implementazione...
        }
         
        final public function parse_my_xml_doc() {
                // implementazione...
        }
         
        final public function sayHello() {
                echo "Hello!";
        }
}
 
$myClass = new MyClass();
 
// stampa "Hello!"
$myClass->sayHello();

// Fatal Error perchè sayHello() è stata dichiarata - final -
// NON POSSO FARE OVERRIDING
class AnotherClass extends MyClass {
        public function sayHello() {
                echo "Hello!";
        }
 
}

Per le classi:


final class MyClass {
        // implementazione...
} 

// Fatal Error: lass AnotherClass may not inherit from final class (MyClass)
lass AnotherClass extends MyClass {
        // implementazione...
}

Il mio sito ufficiale:
www.lucedigitale.com

Bibligrafia:
www.html.it/pag/18341/creare-le-classi/
www.html.it/pag/18353/impedire-loverriding-final/