diff --git a/language/oop5/interfaces.xml b/language/oop5/interfaces.xml new file mode 100644 index 000000000..608589a80 --- /dev/null +++ b/language/oop5/interfaces.xml @@ -0,0 +1,454 @@ + + + + Interfacce degli Oggetti + + Le interfacce degli oggetti permettono di creare codice che specifica quali metodi e proprietà + una classe deve implementare, senza dover definire come tali metodi o proprietà sono + implementati. Le interfacce condividono uno spazio dei nomi con le classi, i trait e le enumerazioni, quindi + non possono utilizzare lo stesso nome. + + + Le interfacce vengono definite allo stesso modo di una classe, ma con la parola chiave interface + al posto della parola chiave class e senza che alcun metodo abbia + il proprio contenuto definito. + + + Tutti i metodi dichiarati in un'interfaccia devono essere pubblici; questa è la natura di + un'interfaccia. + + + In pratica, le interfacce servono a due scopi complementari: + + + + Permettere agli sviluppatori di creare oggetti di classi differenti che possono essere usati + in modo intercambiabile perché implementano la stessa interfaccia o interfacce. Un esempio comune è quello di servizi + multipli per l'accesso ai database, gateway multipli per i pagamenti, o differenti strategie di caching. Le + diverse implementazioni possono essere sostituite senza richiedere alcuna modifica al codice che le utilizza. + + + Permettere a una funzione o metodo di accettare e operare su un parametro conforme a + un'interfaccia, senza preoccuparsi di cos'altro l'oggetto possa fare o di come sia implementato. Queste interfacce + sono spesso nominate come Iterable, Cacheable, Renderable, + e così via per descrivere il significato del comportamento. + + + + Le interfacce possono definire + metodi magici per richiedere alle classi che le implementano + di implementare tali metodi. + + + + Sebbene siano supportati, includere costruttori + nelle interfacce è fortemente sconsigliato. Farlo riduce significativamente la flessibilità dell'oggetto che implementa + l'interfaccia. Inoltre, i costruttori non sono soggetti alle regole di ereditarietà, il che può causare + comportamenti inconsistenti e inattesi. + + + + + <literal>implements</literal> + + Per implementare un'interfaccia, si utilizza l'operatore implements. + Tutti i metodi dell'interfaccia devono essere implementati all'interno della classe; non farlo + causerà un errore fatale. Le classi possono implementare più di un'interfaccia, + se desiderato, separando ciascuna interfaccia con una virgola. + + + + Una classe che implementa un'interfaccia può utilizzare un nome diverso per i propri parametri rispetto + all'interfaccia. Tuttavia, a partire da PHP 8.0 il linguaggio supporta gli argomenti con nome, il che significa + che i chiamanti potrebbero fare affidamento sul nome del parametro nell'interfaccia. Per questa ragione, è fortemente + raccomandato che gli sviluppatori utilizzino gli stessi nomi di parametro dell'interfaccia che viene implementata. + + + + + Le interfacce possono essere estese come le classi utilizzando l'operatore extends. + + + + + La classe che implementa l'interfaccia deve dichiarare tutti i metodi dell'interfaccia + con una firma compatibile. Una classe può implementare più interfacce + che dichiarano un metodo con lo stesso nome. In questo caso, l'implementazione deve seguire le + regole di compatibilità delle firme per tutte le interfacce. Pertanto + è possibile applicare la covarianza e la controvarianza. + + + + + + Costanti + + È possibile per le interfacce avere costanti. Le costanti di interfaccia funzionano esattamente + come le costanti di classe. + Prima di PHP 8.1.0, non potevano essere sovrascritte da una classe/interfaccia che le ereditava. + + + + Proprietà + + A partire da PHP 8.4.0, le interfacce possono anche dichiarare proprietà. + In tal caso, la dichiarazione deve specificare se la proprietà deve essere leggibile, + scrivibile, o entrambi. + La dichiarazione dell'interfaccia si applica solo all'accesso pubblico in lettura e scrittura. + + + Una classe può soddisfare una proprietà di interfaccia in diversi modi. + Può definire una proprietà pubblica. + Può definire una + proprietà virtuale pubblica + che implementa solo l'hook corrispondente. + Oppure una proprietà in lettura può essere soddisfatta da una proprietà readonly. + Tuttavia, una proprietà di interfaccia scrivibile non può essere readonly. + + + Esempio di proprietà di interfaccia + + strtoupper($this->writeable); } + + // L'interfaccia richiede solo che la proprietà sia scrivibile, + // ma includere anche operazioni get è completamente valido. + // Questo esempio crea una proprietà virtuale, il che va bene. + public string $writeable { + get => $this->written; + set { + $this->written = $value; + } + } + + // Questa proprietà richiede che sia la lettura che la scrittura siano possibili, + // quindi è necessario implementare entrambi, o permettere che abbia + // il comportamento predefinito. + public string $both { + get => $this->all; + set { + $this->all = strtoupper($value); + } + } +} +?> +]]> + + + + + &reftitle.examples; + + Esempio di interfaccia + +vars[$name] = $var; + } + + public function getHtml($template) + { + foreach($this->vars as $name => $value) { + $template = str_replace('{' . $name . '}', $value, $template); + } + + return $template; + } +} + +// Questo non funzionerà +// Fatal error: Class BadTemplate contains 1 abstract methods +// and must therefore be declared abstract (Template::getHtml) +class BadTemplate implements Template +{ + private $vars = []; + + public function setVariable($name, $var) + { + $this->vars[$name] = $var; + } +} +?> +]]> + + + + Interfacce estendibili + + +]]> + + + + Compatibilità della varianza con interfacce multiple + + +]]> + + + + Ereditarietà multipla delle interfacce + + +]]> + + + + Interfacce con costanti + + +]]> + + + + Interfacce con classi astratte + + +]]> + + + + Estensione e implementazione simultanee + + +]]> + + + + Un'interfaccia, insieme alle dichiarazioni di tipo, fornisce un buon modo per assicurarsi + che un particolare oggetto contenga particolari metodi. Si vedano + l'operatore instanceof e le + dichiarazioni di tipo. + + + + + + diff --git a/language/oop5/properties.xml b/language/oop5/properties.xml new file mode 100644 index 000000000..f589f0df4 --- /dev/null +++ b/language/oop5/properties.xml @@ -0,0 +1,408 @@ + + + + Proprietà + + + Le variabili membro di una classe sono chiamate proprietà. + Possono essere indicate anche con altri termini come campi, + ma ai fini di questo riferimento verrà utilizzato il termine proprietà. + Sono definite utilizzando almeno un modificatore (come + , + , + oppure, a partire da PHP 8.1.0, readonly), + opzionalmente (tranne per le proprietà readonly), a partire da PHP 7.4, + seguito da una dichiarazione di tipo, seguita da una normale dichiarazione di variabile. + Questa dichiarazione può includere un'inizializzazione, ma questa inizializzazione + deve essere un valore costante. + + + + Un modo obsoleto di dichiarare le proprietà di una classe consiste nell'utilizzare + la parola chiave var al posto di un modificatore. + + + + + Una proprietà dichiarata senza un modificatore di + sarà dichiarata come public. + + + + All'interno dei metodi di una classe, le proprietà non statiche possono essere + accessibili utilizzando -> (Operatore Oggetto): + $this->property + (dove property è il nome della proprietà). + Le proprietà statiche sono accessibili utilizzando :: (Doppio due punti): + self::$property. Vedere + per ulteriori informazioni sulla differenza tra proprietà statiche e non statiche. + + + La pseudo-variabile $this è disponibile all'interno di + qualsiasi metodo di classe quando quel metodo è chiamato dal contesto di un oggetto. + $this è il valore dell'oggetto chiamante. + + + + + Dichiarazioni di proprietà + + +]]> + + + + + + + Esistono diverse funzioni per gestire classi e oggetti. + Vedere il riferimento delle Funzioni Classe/Oggetto. + + + + + Dichiarazioni di tipo + + A partire da PHP 7.4.0, le definizioni delle proprietà possono includere + , + con l'eccezione di callable. + + Esempio di proprietà tipizzate + +id = $id; + $this->name = $name; + } +} + +$user = new User(1234, null); + +var_dump($user->id); +var_dump($user->name); + +?> +]]> + + &example.outputs; + + + + + + + + Le proprietà tipizzate devono essere inizializzate prima dell'accesso, altrimenti + viene lanciato un Error. + + Accesso alle proprietà + +numberOfSides = $numberOfSides; + } + + public function setName(string $name): void + { + $this->name = $name; + } + + public function getNumberOfSides(): int + { + return $this->numberOfSides; + } + + public function getName(): string + { + return $this->name; + } +} + +$triangle = new Shape(); +$triangle->setName("triangle"); +$triangle->setNumberofSides(3); +var_dump($triangle->getName()); +var_dump($triangle->getNumberOfSides()); + +$circle = new Shape(); +$circle->setName("circle"); +var_dump($circle->getName()); +var_dump($circle->getNumberOfSides()); +?> +]]> + + &example.outputs; + + + + + + + + + Proprietà readonly + + A partire da PHP 8.1.0, una proprietà può essere dichiarata con il modificatore readonly, + che impedisce la modifica della proprietà dopo l'inizializzazione. Prima di PHP 8.4.0 + una proprietà readonly è implicitamente private-set, e può essere scritta solo + dalla stessa classe. A partire da PHP 8.4.0, le proprietà readonly sono implicitamente + protected(set), + quindi possono essere impostate dalle classi figlie. Questo comportamento può essere sovrascritto + esplicitamente se desiderato. + + Esempio di proprietà readonly + +prop = $prop; + } +} + +$test = new Test("foobar"); +// Lettura valida. +var_dump($test->prop); // string(6) "foobar" + +// Riassegnamento non valido. Non importa che il valore assegnato sia lo stesso. +$test->prop = "foobar"; +// Error: Cannot modify readonly property Test::$prop +?> +]]> + + + + + Il modificatore readonly può essere applicato solo a proprietà tipizzate. + Una proprietà readonly senza vincoli di tipo può essere creata utilizzando il tipo . + + + + + Le proprietà statiche readonly non sono supportate. + + + + + Una proprietà readonly può essere inizializzata solo una volta, e solo dallo scope in cui è stata dichiarata. Qualsiasi altra assegnazione o modifica della proprietà risulterà in un'eccezione Error. + + Inizializzazione non valida delle proprietà readonly + +prop = "foobar"; +// Error: Cannot initialize readonly property Test1::$prop from global scope +?> +]]> + + + + + + Non è consentito specificare un valore predefinito esplicito per le proprietà readonly, poiché una proprietà readonly con un valore predefinito è essenzialmente uguale a una costante, e quindi non particolarmente utile. + + + +]]> + + + + + + + Le proprietà readonly non possono essere annullate con unset una volta inizializzate. Tuttavia, è possibile annullare una proprietà readonly prima dell'inizializzazione, dallo scope in cui la proprietà è stata dichiarata. + + + + Le modifiche non sono necessariamente semplici assegnamenti, anche tutte le seguenti operazioni risulteranno in un'eccezione Error: + + +i += 1; +$test->i++; +++$test->i; +$test->ary[] = 1; +$test->ary[0][] = 1; +unset($test->ary[0]); +$ref =& $test->i; +$test->i =& $ref; +byRef($test->i); +foreach ($test as &$prop); +?> +]]> + + + + + Tuttavia, le proprietà readonly non impediscono la mutabilità interna. Gli oggetti (o le risorse) memorizzati nelle proprietà readonly possono comunque essere modificati internamente: + + +obj->foo = 1; +// Riassegnamento non valido. +$test->obj = new stdClass; +?> +]]> + + + + + A partire da PHP 8.3.0, le proprietà readonly possono essere reinizializzate durante la clonazione + di un oggetto utilizzando il metodo __clone(). + + Proprietà readonly e clonazione + +prop = null; + } + + public function setProp(string $prop): void { + $this->prop = $prop; + } +} + +$test1 = new Test1; +$test1->setProp('foobar'); + +$test2 = clone $test1; +var_dump($test2->prop); // NULL +?> +]]> + + + + + + + Proprietà dinamiche + + Se si tenta di assegnare un valore a una proprietà inesistente su un &object;, + PHP creerà automaticamente una proprietà corrispondente. + Questa proprietà creata dinamicamente sarà disponibile solo + su questa istanza della classe. + + + + + Le proprietà dinamiche sono deprecate a partire da PHP 8.2.0. + Si raccomanda di dichiarare la proprietà esplicitamente. + Per gestire nomi di proprietà arbitrari, la classe dovrebbe implementare i metodi + magici __get() e + __set(). + Come ultima risorsa, la classe può essere contrassegnata con l'attributo + #[\AllowDynamicProperties]. + + + + + + diff --git a/language/oop5/visibility.xml b/language/oop5/visibility.xml new file mode 100644 index 000000000..ed3043e49 --- /dev/null +++ b/language/oop5/visibility.xml @@ -0,0 +1,480 @@ + + + + Visibilità + + La visibilità di una proprietà, di un metodo o (a partire da PHP 7.1.0) di una costante può essere definita + anteponendo alla dichiarazione le parole chiave public, + protected o + private. I membri della classe dichiarati public sono + accessibili ovunque. I membri dichiarati protected sono accessibili + solo all'interno della classe stessa e dalle classi che la ereditano + e dalle classi genitore. I membri dichiarati come private possono essere + accessibili solo dalla classe che definisce il membro. + + + + Visibilità delle proprietà + + Le proprietà della classe possono essere definite come public, private o + protected. Le proprietà dichiarate senza alcuna parola chiave di + visibilità esplicita sono definite come public. + + + Dichiarazione delle proprietà + +public; + echo $this->protected; + echo $this->private; + } +} + +$obj = new MyClass(); +echo $obj->public; // Funziona +echo $obj->protected; // Errore Fatale +echo $obj->private; // Errore Fatale +$obj->printHello(); // Mostra Public, Protected e Private + + +/** + * Definizione di MyClass2 + */ +class MyClass2 extends MyClass +{ + // Possiamo ridichiarare le proprietà public e protected, ma non private + public $public = 'Public2'; + protected $protected = 'Protected2'; + + function printHello() + { + echo $this->public; + echo $this->protected; + echo $this->private; + } +} + +$obj2 = new MyClass2(); +echo $obj2->public; // Funziona +echo $obj2->protected; // Errore Fatale +echo $obj2->private; // Non definito +$obj2->printHello(); // Mostra Public2, Protected2, Non definito + +?> +]]> + + + + Visibilità asimmetrica delle proprietà + + A partire da PHP 8.4, le proprietà degli oggetti possono anche avere la loro + visibilità impostata in modo asimmetrico, con un ambito diverso per + la lettura (get) e la scrittura (set). + Nello specifico, la visibilità set può essere + specificata separatamente, a condizione che non sia più permissiva della + visibilità predefinita. + + + Visibilità asimmetrica delle proprietà + +author = $author; // OK + $this->pubYear = $year; // Errore Fatale + } +} + +$b = new Book('How to PHP', 'Peter H. Peterson', 2024); + +echo $b->title; // Funziona +echo $b->author; // Funziona +echo $b->pubYear; // Errore Fatale + +$b->title = 'How not to PHP'; // Errore Fatale +$b->author = 'Pedro H. Peterson'; // Errore Fatale +$b->pubYear = 2023; // Errore Fatale +?> +]]> + + + + A partire da PHP 8.5, la visibilità set può essere applicata anche alle proprietà statiche delle classi. + + + Visibilità asimmetrica delle proprietà statiche + +doAThing(); // Funziona +echo Manager::$calls; // Funziona +Manager::$calls = 5; // Errore fatale +?> +]]> + + &example.outputs; + + + + + Ci sono alcune avvertenze riguardo alla visibilità asimmetrica: + + + + Solo le proprietà tipizzate possono avere una visibilità set separata. + + + + + La visibilità set deve essere la stessa + di get o più restrittiva. Cioè significa che + public protected(set) e protected protected(set) + sono permessi, ma protected public(set) causerà un errore di sintassi. + + + + + Se una proprietà è public, allora la visibilità principale può essere + omessa. Cioè significa che public private(set) e private(set) + avranno lo stesso risultato. + + + + + Una proprietà con visibilità private(set) + è automaticamente final e non può essere ridichiarata in una classe figlia. + + + + + Ottenere un riferimento a una proprietà segue la visibilità set, non get. + Questo perché un riferimento può essere usato per modificare il valore della proprietà. + + + + + Analogamente, cercare di scrivere su una proprietà array implica sia un'operazione get che + set internamente, e pertanto seguirà la visibilità set, + poiché è sempre la più restrittiva. + + + + + + Gli spazi non sono permessi nella dichiarazione della visibilità set. + private(set) è corretto. + private( set ) non è corretto e causerà un errore di analisi. + + + + Quando una classe estende un'altra, la classe figlia può ridefinire + qualsiasi proprietà che non sia final. Nel farlo, + può ampliare sia la visibilità principale che la visibilità set, + a condizione che la nuova visibilità sia la stessa o più ampia + di quella della classe genitore. Tuttavia, bisogna tenere presente che se una proprietà + private viene sovrascritta, in realtà non cambia la proprietà del genitore + ma crea una nuova proprietà con un nome interno diverso. + + + Ereditarietà delle proprietà asimmetriche + + +]]> + + + + + + + Visibilità dei metodi + + I metodi della classe possono essere definiti come public, private o + protected. I metodi dichiarati senza alcuna parola chiave di + visibilità esplicita sono definiti come public. + + + Dichiarazione dei metodi + +MyPublic(); + $this->MyProtected(); + $this->MyPrivate(); + } +} + +$myclass = new MyClass; +$myclass->MyPublic(); // Funziona +$myclass->MyProtected(); // Errore Fatale +$myclass->MyPrivate(); // Errore Fatale +$myclass->Foo(); // Public, Protected e Private funzionano + + +/** + * Definizione di MyClass2 + */ +class MyClass2 extends MyClass +{ + // Questo è public + function Foo2() + { + $this->MyPublic(); + $this->MyProtected(); + $this->MyPrivate(); // Errore Fatale + } +} + +$myclass2 = new MyClass2; +$myclass2->MyPublic(); // Funziona +$myclass2->Foo2(); // Public e Protected funzionano, Private no + +class Bar +{ + public function test() { + $this->testPrivate(); + $this->testPublic(); + } + + public function testPublic() { + echo "Bar::testPublic\n"; + } + + private function testPrivate() { + echo "Bar::testPrivate\n"; + } +} + +class Foo extends Bar +{ + public function testPublic() { + echo "Foo::testPublic\n"; + } + + private function testPrivate() { + echo "Foo::testPrivate\n"; + } +} + +$myFoo = new Foo(); +$myFoo->test(); // Bar::testPrivate + // Foo::testPublic +?> +]]> + + + + + + Visibilità delle costanti + + A partire da PHP 7.1.0, le costanti di classe possono essere definite come public, private o + protected. Le costanti dichiarate senza alcuna parola chiave di + visibilità esplicita sono definite come public. + + + Dichiarazione delle costanti a partire da PHP 7.1.0 + +foo(); // Public, Protected e Private funzionano + + +/** + * Definizione di MyClass2 + */ +class MyClass2 extends MyClass +{ + // Questo è public + function foo2() + { + echo self::MY_PUBLIC; + echo self::MY_PROTECTED; + echo self::MY_PRIVATE; // Errore Fatale + } +} + +$myclass2 = new MyClass2; +echo MyClass2::MY_PUBLIC; // Funziona +$myclass2->foo2(); // Public e Protected funzionano, Private no +?> +]]> + + + + + + Visibilità da altri oggetti + + Gli oggetti dello stesso tipo avranno accesso ai membri private e + protected l'uno dell'altro anche se non sono le stesse istanze. Questo perché + i dettagli specifici dell'implementazione sono già noti quando ci si trova + all'interno di quegli oggetti. + + + Accesso ai membri private dello stesso tipo di oggetto + +foo = $foo; + } + + private function bar() + { + echo 'Accessed the private method.'; + } + + public function baz(Test $other) + { + // Possiamo modificare la proprietà private: + $other->foo = 'hello'; + var_dump($other->foo); + + // Possiamo anche chiamare il metodo private: + $other->bar(); + } +} + +$test = new Test('test'); + +$test->baz(new Test('other')); +?> +]]> + + &example.outputs; + + + + + + +