Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
389 changes: 389 additions & 0 deletions language/attributes.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,389 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 0f14761ba340c6e49797706ac3f0cf1147d97253 Maintainer: lacatoire Status: ready -->
<chapter xml:id="language.attributes" xmlns="http://docbook.org/ns/docbook">
<title>Attributi</title>
<sect1 xml:id="language.attributes.overview">
<title>Panoramica sugli attributi</title>
<?phpdoc print-version-for="attributes"?>

<para>
Gli attributi PHP forniscono metadati strutturati e leggibili dalla macchina per classi, metodi,
funzioni, parametri, proprietà e costanti. Possono essere ispezionati a runtime
tramite la <link linkend="book.reflection">Reflection API</link>, abilitando un comportamento
dinamico senza modificare il codice. Gli attributi forniscono un modo dichiarativo per annotare
il codice con metadati.
</para>
<para>
Gli attributi permettono di disaccoppiare l'implementazione di una funzionalità dal suo utilizzo. Mentre
le interfacce definiscono la struttura imponendo metodi, gli attributi forniscono metadati su più
elementi, inclusi metodi, funzioni, proprietà e costanti. A differenza delle interfacce,
che impongono l'implementazione dei metodi, gli attributi annotano il codice senza alterarne la struttura.
</para>
<para>
Gli attributi possono completare o sostituire i metodi opzionali delle interfacce fornendo metadati invece di
una struttura imposta. Si consideri un'interfaccia <literal>ActionHandler</literal> che rappresenta
un'operazione in un'applicazione. Alcune implementazioni possono richiedere un passo di configurazione mentre altre no.
Invece di forzare tutte le classi che implementano <literal>ActionHandler</literal> a definire un
metodo <literal>setUp()</literal>, un attributo può indicare i requisiti di configurazione. Questo approccio
aumenta la flessibilità, permettendo di applicare gli attributi più volte quando necessario.
</para>

<example>
<title>Implementazione di metodi opzionali di un'interfaccia con gli Attributi</title>
<programlisting role="php">
<![CDATA[
<?php
interface ActionHandler
{
public function execute();
}

#[Attribute]
class SetUp {}

class CopyFile implements ActionHandler
{
public string $fileName;
public string $targetDirectory;

#[SetUp]
public function fileExists()
{
if (!file_exists($this->fileName)) {
throw new RuntimeException("File does not exist");
}
}

#[SetUp]
public function targetDirectoryExists()
{
if (!file_exists($this->targetDirectory)) {
mkdir($this->targetDirectory);
} elseif (!is_dir($this->targetDirectory)) {
throw new RuntimeException("Target directory $this->targetDirectory is not a directory");
}
}

public function execute()
{
copy($this->fileName, $this->targetDirectory . '/' . basename($this->fileName));
}
}

function executeAction(ActionHandler $actionHandler)
{
$reflection = new ReflectionObject($actionHandler);

foreach ($reflection->getMethods() as $method) {
$attributes = $method->getAttributes(SetUp::class);

if (count($attributes) > 0) {
$methodName = $method->getName();

$actionHandler->$methodName();
}
}

$actionHandler->execute();
}

$copyAction = new CopyFile();
$copyAction->fileName = "/tmp/foo.jpg";
$copyAction->targetDirectory = "/home/user";

executeAction($copyAction);
]]>
</programlisting>
</example>
</sect1>

<sect1 xml:id="language.attributes.syntax">
<title>Sintassi degli attributi</title>

<para>
La sintassi degli attributi è composta da diversi elementi chiave. Una dichiarazione
di attributo inizia con <literal>#[</literal> e termina con
<literal>]</literal>. All'interno, è possibile elencare uno o più attributi,
separati da virgole. Il nome dell'attributo può essere non qualificato, qualificato
o completamente qualificato, come descritto in <link linkend="language.namespaces.basics">Utilizzo base dei Namespace</link>.
Gli argomenti dell'attributo sono opzionali e racchiusi tra parentesi
<literal>()</literal>. Gli argomenti possono essere solo valori letterali o espressioni
costanti. È supportata sia la sintassi con argomenti posizionali che quella con argomenti nominati.
</para>

<para>
I nomi degli attributi e i loro argomenti vengono risolti in una classe, e gli argomenti
vengono passati al suo costruttore quando un'istanza dell'attributo viene richiesta
tramite la Reflection API. Pertanto, è raccomandato introdurre una classe
per ogni attributo.
</para>

<example>
<title>Sintassi degli Attributi</title>

<programlisting role="php">
<![CDATA[
<?php
// a.php
namespace MyExample;

use Attribute;

#[Attribute]
class MyAttribute
{
const VALUE = 'value';

private $value;

public function __construct($value = null)
{
$this->value = $value;
}
}

// b.php

namespace Another;

use MyExample\MyAttribute;

#[MyAttribute]
#[\MyExample\MyAttribute]
#[MyAttribute(1234)]
#[MyAttribute(value: 1234)]
#[MyAttribute(MyAttribute::VALUE)]
#[MyAttribute(array("key" => "value"))]
#[MyAttribute(100 + 200)]
class Thing
{
}

#[MyAttribute(1234), MyAttribute(5678)]
class AnotherThing
{
}
]]>
</programlisting>
</example>
</sect1>


<sect1 xml:id="language.attributes.reflection">
<title>Leggere gli attributi con la Reflection API</title>

<para>
Per accedere agli attributi da classi, metodi, funzioni, parametri, proprietà
e costanti di classe, si utilizza il metodo <function>getAttributes</function> fornito
dalla Reflection API. Questo metodo restituisce un array di istanze di <classname>ReflectionAttribute</classname>.
Queste istanze possono essere interrogate per ottenere il nome dell'attributo, gli argomenti, e
possono essere utilizzate per creare un'istanza dell'attributo rappresentato.
</para>

<para>
Separare la rappresentazione riflessa dell'attributo dalla sua istanza effettiva fornisce un maggiore
controllo sulla gestione degli errori, come classi di attributi mancanti, argomenti errati
o valori mancanti. Gli oggetti della classe attributo vengono istanziati solo dopo la chiamata a
<function>ReflectionAttribute::newInstance</function>, garantendo che la validazione degli argomenti
avvenga in quel momento.
</para>

<example>
<title>Lettura degli attributi utilizzando la Reflection API</title>

<programlisting role="php">
<![CDATA[
<?php

#[Attribute]
class MyAttribute
{
public $value;

public function __construct($value)
{
$this->value = $value;
}
}

#[MyAttribute(value: 1234)]
class Thing
{
}

function dumpAttributeData($reflection) {
$attributes = $reflection->getAttributes();

foreach ($attributes as $attribute) {
var_dump($attribute->getName());
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
}
}

dumpAttributeData(new ReflectionClass(Thing::class));
/*
string(11) "MyAttribute"
array(1) {
["value"]=>
int(1234)
}
object(MyAttribute)#3 (1) {
["value"]=>
int(1234)
}
*/

]]>
</programlisting>
</example>

<para>
Invece di iterare su tutti gli attributi dell'istanza di riflessione,
è possibile recuperare solo quelli di una specifica classe di attributo passando
il nome della classe attributo come argomento.
</para>

<example>
<title>Lettura di attributi specifici utilizzando la Reflection API</title>

<programlisting role="php">
<![CDATA[
<?php

function dumpMyAttributeData($reflection) {
$attributes = $reflection->getAttributes(MyAttribute::class);

foreach ($attributes as $attribute) {
var_dump($attribute->getName());
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
}
}

dumpMyAttributeData(new ReflectionClass(Thing::class));
]]>
</programlisting>
</example>
</sect1>

<sect1 xml:id="language.attributes.classes">
<title>Dichiarazione delle classi attributo</title>

<para>
È raccomandato definire una classe separata per ogni attributo. Nel caso più semplice,
è sufficiente una classe vuota con la dichiarazione <literal>#[Attribute]</literal>.
L'attributo può essere importato dal namespace globale utilizzando un'istruzione
<literal>use</literal>.
</para>

<example>
<title>Classe attributo semplice</title>

<programlisting role="php">
<![CDATA[
<?php

namespace Example;

use Attribute;

#[Attribute]
class MyAttribute
{
}
]]>
</programlisting>
</example>

<para>
Per limitare i tipi di dichiarazioni a cui un attributo può essere applicato,
è possibile passare una bitmask come primo argomento alla dichiarazione
<literal>#[Attribute]</literal>.
</para>

<example>
<title>Utilizzo della specifica del target per limitare dove gli attributi possono essere usati</title>

<programlisting role="php">
<![CDATA[
<?php

namespace Example;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class MyAttribute
{
}
]]>
</programlisting>

<para>
Dichiarare <classname>MyAttribute</classname> su un altro tipo genererà ora un'eccezione durante
la chiamata a <function>ReflectionAttribute::newInstance</function>
</para>
</example>

<para>È possibile specificare i seguenti target:</para>

<simplelist>
<member><constant>Attribute::TARGET_CLASS</constant></member>
<member><constant>Attribute::TARGET_FUNCTION</constant></member>
<member><constant>Attribute::TARGET_METHOD</constant></member>
<member><constant>Attribute::TARGET_PROPERTY</constant></member>
<member><constant>Attribute::TARGET_CLASS_CONSTANT</constant></member>
<member><constant>Attribute::TARGET_PARAMETER</constant></member>
<member><constant>Attribute::TARGET_ALL</constant></member>
</simplelist>

<para>
Per impostazione predefinita, un attributo può essere utilizzato solo una volta per dichiarazione. Per
permettere a un attributo di essere ripetibile, è necessario specificarlo nella bitmask della
dichiarazione <literal>#[Attribute]</literal> utilizzando il flag
<constant>Attribute::IS_REPEATABLE</constant>.
</para>

<example>
<title>Utilizzo di IS_REPEATABLE per permettere un attributo su una dichiarazione più volte</title>

<programlisting role="php">
<![CDATA[
<?php

namespace Example;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION | Attribute::IS_REPEATABLE)]
class MyAttribute
{
}
]]>
</programlisting>

</example>
</sect1>
</chapter>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->
Loading