"Sono stato bocciato a parecchi esami. Un mio amico invece, li ha passati tutti a pieni voti. Ora è ingegnere e lavora in Microsoft. Io sono il proprietario."  - Bill Gates  •  "Se riesco a fare qualcosa in 10 minuti, è perché ho passato anni a studiarlo."  - Bill Gates  •  "Il vostro lavoro riempirà gran parte della vostra vita, e l'unico modo per essere veramente soddisfatti è fare ciò che ritenete sia un grande lavoro."  - Steve Jobs  •  "Siate affamati. Siate folli."  - Steve Jobs  •  

cinque 

ZERO

PHP

< ? PHP ?> Classi, costruttori, costruttori multipli, distruttori e indicatori di visibilità

home / php /

Lucio Paolo Asciolla

Senior Full Stack Developer

La Classi

La sintassi per creare una classe in php è la seguente :

class Persona{

private $nome = "";
private $cognome = "";

public function __construct( $nome, $cognome ){
$this->nome = $nome;
$this->cognome = $cognome;
}

public function mostraNome(){
return $this->nome;
}

}

Una classe si definisce mediante la parola chiave "class";
possiamo inizializzare subito delle variabili utili al costruttore stesso mediante la parola chiave "private";
la funzione defnita "public" rappresenta il core del costruttore; è pubblica per permettere gli istanziamenti; attraverso la variabile "$this" assegna i valori passati al momento della creazione di un nuovo oggetto.
"mostraNome" è un metodo definito per tutte le istanze.

Indicatori di visibilità

Nello snippet di codice precedente abbiamo utilizzato le parole chiavi "private" e "public"; queste rappresentano indicatori di visibilità dei dati all'interno delle classi.
Esistono tre tipi di indicatori di visibilità:

IndicatoreDescrizione
publicI membri (proprietà o metodi) dichiarati public sono accessibili sia dall'interno che dall'esterno della classe e dalle classi derivate da essa (viene quindi introdotto il concetto di ereditarietà di cui parleremo nei prossimi capitoli).
protectedI membri dichiarati protected, possono essere utilizzati all'interno della classe stessa e all'interno delle classi derivate, ma non sono accessibili dall'esterno della classe.
privateI membri dichiarati private, possono essere utilizzati soltanto all'interno della classe stessa.

$this

Come accade in altri linguaggi oop la varabile "$this"  rappresenta l'oggetto costruito a runtime ovvero farà riferimento all'oggetto che ci si appresta ad istanziare.

__construct

All'interno della prima funzione "pubblica", che è il costruttore della classe, abbiamo abbiamo utilizzato un "metodo magico" disponibile in PHP  "__construct";

I "metodi magici" nella OOP di PHP, sono metodi che si attivano al verificarsi di determinati eventi; contrassegnati dal doppio underscore __ iniziale.

__destruct

"__destruct" rappresenta un'altro metodo magico disponibile in php.
Questo metodo, viene chiamato automaticamente dal motore di PHP prima che l'oggetto sia distrutto ed utile, ad esempio, per richiedere di chiudere handle dei files, le connessioni al database o operazioni da eseguire prima che l'oggetto venga distrutto. 

Istanziare una classe

Creato il nostro costruttore possiamo istanziare nuovi oggetti mediante la parola chiave "new"

$primaPersona = new Persona("Guido", "Bianchi");

Accedere alle proprietà dell'oggetto creato

A differenza di altri linguaggi per accedere alle proprietà e metodi di un oggetto utilizzeremo la seguente sintassi "->"

echo $primaPersona->nome;
echo $primaPersona->cognome;
echo $primaPersona->mostraNome();

Classi multiple

PHP non supporta nativamente i costruttori multipli nelle classi, ogni classe può avere infatti un unico metodo costruttore; esistono metodi aggirare questa limitazione.

Static

Prima di procedere dobbiamo definire i diversi ruoli che può assumere la keyword "static".

Al di fuori di una classe, "static" intesa come variabile, è una variabile che non perde il suo valore quando la funzione termina.
Il suo valore viene mantenuto attraverso diverse invocazioni della stessa funzione.

function miaFunzione(){
    static $numero = 0;
    echo $numero;
    $numero ++;
}

miaFunzione();  // stampa 0
miaFunzione();  // stampa 1
miaFunzione();  // stampa 2

La parola chiave "static" nel contesto delle classi si comporta in maniera differente. 
Un metodo o una variabile dichiarata "static" è associato unicamente alla classe in cui è dichiarate e non è trasferita ad un'istanza di tale classe. 
Pertanto, puoi accedervi non da una istanza della classe ma dalla classe stessa usando "classe::$var"

class Classe{
  public static $var = 'value'; // $var è static (nel contesto di una classe)
  public $altra_var = 'alto_value'; // $altra_var non è una variabile statica
}

echo Classe::$var; // accede è stampa "value"
echo Classe::$altra_var // Fatal Error, non è possibile accedere in questo modo in quanto non si tratta di una variabile statica

$variabile = new Classe;
echo $a->var // Non è possible accedere (strict standards)
echo $a->altra_var // accede è stampa "altro_value"

Scope Resolution Operator

L'operatore di risoluzione dell'ambito (chiamato anche Paamayim Nekudotayim), i due punti doppi "::" , è un token che consente l'accesso a proprietà o metodi statici, costanti di una classe.
In parole semplici è usato per chiamare i metodi e le variabili statiche di una classe.

self::

Una classe può contenere variabili e metodi che sono trasferiti alle proprie istanze o di tipo statico che sono riservati ed accessibili, come visto precedentemente, esclusivamente dalla classe stessa.
Se abbiamo la necessità di utilizzare all'interno della stessa classe un dato definito statico possiamo utilizzare la parola chiave "self"

class Classe{
    public static function metodo(){
        echo "Questo è il primo metodo.";
    }
    public static function secondoMetodo(){
        self::metodo();
    }
}
 
Classe::metodo(); // Questo è il primo metodo.
Classe::secondoMetodo(); // Questo è il primo metodo.

Facciamo un esempio con un estensione di classe:

class Classe{  
    public static function secondoMetodo(){
        echo "Questo è il secondo metodo.";
    }
    public static function metodo(){
        self::secondoMetodo();
    }  
}

class SecondaClasse extends Classe{
   public static function secondoMetodo() {
        echo "Questo è un secondo metodo maggiore.";
    }
   
}

Classe::metodo(); // Questo è il secondo metodo.
SecondaClasse::metodo(); // Questo è il secondo metodo.
SecondaClasse::secondoMetodo(); // Questo è un secondo metodo maggiore.

new self() & new static()

Ora che abbiamo cambiato quando usare static e quando usare self, è chiaro che "self" fa riferimento alla classe corrente, mentre "static" consente alla funzione (variabili, costanti ecc.) di legarsi alla classe in tempo di esecuzione. 

Di queste stesse keyword sono disponibili due metodi.


Chiariamo il tutto con questo esempio:

class Classe{
      
    // new self()
    public static function mostra_self(){
    return new self();
    }
   
    // new static()
    public static function mostra_static(){
    return new static();
    }
}
   
class secondaClasse extends Classe{
}
   
echo get_class(secondaClasse::mostra_self()); // Classe
echo get_class(secondaClasse::mostra_static()); // SecondaClasse
echo get_class(Classe::mostra_self()); // Classe

"new self()" e "new static()" restituiscono un oggetto che si lega al proprio relativo ambito.

Con la funzione "get_class()" recuperiamo la classe di appartenenza dell'oggetto creato.

Il funzionamento di tali metodi è evidente quando lavoriamo con classi estese.

Factory Pattern

Il primo metodo per integrare costruttori multipli è quello di adottare il design factory pattern assieme a quanto visto poco sopra

class gestioneDate{
    private $stampaData;
    private function __construct(){ 
}
    public static function dataCorrente(){
        $tempo = new static();
        $tempo->stampaData = time();
        return $tempo;
    }
    public static function fromTimestamp($stampaData){
        $tempo = new static();
        $tempo->stampaData = $stampaData ;
        return $tempo;
    }

In questo snippet dichiariamo il costruttore privo di corpo per utilizzare i metodi statici per istanziare oggetti dalla classe.

Questo ci consente di identificare il costrutto come classe-costruttrice per poi gestire le operazioni possibili mediante i metodi statici che saranno accessibili dalla classe principale "gestioneDate".

$dataCorrente = gestioneDate::dataCorrente();

Esaminiamo il metodo "dataCorrente()", uno dei metodi statici definiti:

...
public static function dataCorrente(){
        $tempo = new static();
        $tempo->stampaData = time();
        return $tempo;
    }
...
...
definiamo un metodo pubblico statico "dataCorrente()"{
definiamo una variabile che sarà un oggetto statico della classe "new static()"
assegniamo alla proprietà "stampaData" dell'oggetto creato il valore della data corrente "time()"
restituiamo l'oggetto appena configurato
}
...

proviamo a stampare il risultato:

$dataCorrente = gestioneDate::dataCorrente();
print_r($dataCorrente);
gestioneDate Object ( [stampaData:gestioneDate:private] => 1668552559 )

Factory pattern in style JS

Partiamo da come si definisce un oggetto "semplice" in php

Definire oggetto in php

class marioSaluti{
$nome = 'Mario';
$cognome ='Rossi';

function sauto_buongiorno($nome, $cognome){
echo 'Buongiorno, ' . $nome . $cognome;

function sauto_buonasera($nome, $cognome){
echo 'Buona sera, ' . $nome . $cognome;

}
}

In php un oggetto è sempre una classe con la differenza che non implementa, gestisce, il metodo costruttore "__construct or"

class AutoAds{
private $marca;
private $porte;
privare $motore;
private $airbag;
public function __costructor($marca,$porte,$motore,$airbag){
this->marca= $marca;
this->porte= $porte;
this->motore= $motore;
this->airbag= $airbag;
}
public function showAds(){
echo "Dettagli automobile:<br>" . "Marca " . this->$marca . "<br>" . "Airbag " . this->$airbag . "<br>" . "Marca " . this->$marca . "<br>" . "Numero porte " . this->$porte . "<br>" . "Motore " . this->$motore . "<br>";
}
}

class MotoAds{
private $marca;
private $specchietti;
privare $cilindrata;
private $tipologia;
public function __costructor($marca,$specchietti,$cilindrata,$tipologia){
this->marca= $marca;
this->specchietti= $specchietti;
this->cilindrata= $cilindrata;
this->tipologia= $tipologia;
}
public function showAds(){
echo "Dettagli Moto:<br>" . "Marca " . this->$marca . "<br>" . "Specchietti " . this->$specchietti . "<br>" . "Marca " . this->$marca . "<br>" . "Numero porte " . this->$porte . "<br>" . "Motore " . this->$motore . "<br>";
}
}


class AdsFactory{}


var fabbricaDiAnnunci = {
    creaAnnuncio: function(dati) {
        var annuncio;
        if (dati && dati[0]) {
            switch (dati[0]) {
                case "Immobile":
                    annuncio = new Immobile(dati);
                    break;
                case "Automobile":
                    annuncio = new Automobile(dati);
                    break;
                case "Moto":
                    annuncio = new Moto(dati);
                    break;
            }
        }
        return annuncio;
    }
};