mirror of
https://github.com/php/doc-es.git
synced 2026-03-24 07:22:16 +01:00
392 lines
11 KiB
XML
392 lines
11 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- $Revision$ -->
|
|
<!-- EN-Revision: 0f14761ba340c6e49797706ac3f0cf1147d97253 Maintainer: Marqitos Status: ready -->
|
|
<!-- Reviewed: no -->
|
|
<chapter xml:id="language.attributes" xmlns="http://docbook.org/ns/docbook">
|
|
<title>Atributos</title>
|
|
<sect1 xml:id="language.attributes.overview">
|
|
<title>Descripción general de atributos</title>
|
|
<?phpdoc print-version-for="attributes"?>
|
|
|
|
<para>
|
|
Los atributos de PHP ofrecen metadatos estructurados y legibles por máquinas para clases, métodos,
|
|
funciones, parámetros, propiedades y constantes. Pueden ser inspeccionados en tiempo de ejecución
|
|
a través de la <link linkend="book.reflection">API de Reflection</link>, lo que permite un
|
|
comportamiento dinámico sin modificar el código. Los atributos proporcionan una forma declarativa de anotar
|
|
el código con metadatos.
|
|
</para>
|
|
<para>
|
|
Los atributos permiten desacoplar la implementación de una funcionalidad de su uso. Mientras que
|
|
las interfaces definen la estructura mediante la imposición de métodos, los atributos proporcionan metadatos en
|
|
varios elementos, incluidos métodos, funciones, propiedades y constantes. A diferencia de las interfaces,
|
|
que obligan a implementar métodos, los atributos anotan el código sin alterar su estructura.
|
|
</para>
|
|
<para>
|
|
Los atributos pueden complementar o reemplazar métodos opcionales de una interfaz al proporcionar metadatos en lugar de
|
|
una estructura impuesta. Considera una interfaz <literal>ActionHandler</literal> que representa una
|
|
operación en una aplicación. Algunas implementaciones pueden necesitar un paso de configuración, mientras que otras no.
|
|
En lugar de obligar a todas las clases que implementan <literal>ActionHandler</literal> a definir un
|
|
método <literal>setUp()</literal>, un atributo puede indicar los requisitos de configuración. Este enfoque
|
|
aumenta la flexibilidad, permitiendo que los atributos se apliquen varias veces cuando sea necesario.
|
|
</para>
|
|
|
|
<example>
|
|
<title>Implementación de métodos opcionales de una interfaz mediante atributos</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("El archivo no existe");
|
|
}
|
|
}
|
|
|
|
#[SetUp]
|
|
public function targetDirectoryExists()
|
|
{
|
|
if (!file_exists($this->targetDirectory)) {
|
|
mkdir($this->targetDirectory);
|
|
} elseif (!is_dir($this->targetDirectory)) {
|
|
throw new RuntimeException("El directorio de destino $this->targetDirectory no es un directorio");
|
|
}
|
|
}
|
|
|
|
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>Sintaxis de atributos</title>
|
|
|
|
<para>
|
|
La sintaxis de atributos consta de varios componentes clave. Una declaración
|
|
de atributo comienza con <literal>#[</literal> y termina con
|
|
<literal>]</literal>. Dentro de esta, se pueden listar uno o más atributos,
|
|
separados por comas. El nombre del atributo puede ser no cualificado, cualificado
|
|
o totalmente cualificado, como se describe en <link linkend="language.namespaces.basics">Uso de los espacios de nombres: lo básico</link>.
|
|
Los argumentos para el atributo son opcionales y se encierran entre paréntesis
|
|
<literal>()</literal>. Los argumentos solo pueden ser valores literales o expresiones
|
|
constantes. Se admite la sintaxis de argumentos posicionales y nombrados.
|
|
</para>
|
|
|
|
<para>
|
|
Los nombres de los atributos y sus argumentos se resuelven en una clase, y los argumentos
|
|
se pasan a su constructor cuando se solicita una instancia del atributo
|
|
a través de la API de Reflection. Por lo tanto, se recomienda crear una clase
|
|
para cada atributo.
|
|
</para>
|
|
|
|
<example>
|
|
<title>Sintaxis de atributos</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>Lectura de atributos con la API de Reflection</title>
|
|
|
|
<para>
|
|
Para acceder a los atributos de clases, métodos, funciones, parámetros, propiedades
|
|
y constantes de clase, utiliza el método <function>getAttributes</function> proporcionado
|
|
por la API de Reflection. Este método devuelve un array de instancias de <classname>ReflectionAttribute</classname>.
|
|
Estas instancias pueden consultarse para obtener el nombre del atributo, los argumentos, y
|
|
también pueden usarse para instanciar una instancia del atributo representado.
|
|
</para>
|
|
|
|
<para>
|
|
Separar la representación reflejada del atributo de su instancia real proporciona un mayor
|
|
control sobre la gestión de errores, como clases de atributos faltantes, argumentos mal escritos,
|
|
o valores ausentes. Los objetos de la clase de atributo se instancian solo después de llamar a
|
|
<function>ReflectionAttribute::newInstance</function>, lo que garantiza que la validación de los argumentos
|
|
se realice en ese momento.
|
|
</para>
|
|
|
|
<example>
|
|
<title>Lectura de atributos con la API de Reflection</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>
|
|
En lugar de iterar sobre todos los atributos en la instancia de reflexión,
|
|
puedes recuperar solo aquellos de una clase de atributo específica pasando
|
|
el nombre de la clase de atributo como argumento.
|
|
</para>
|
|
|
|
<example>
|
|
<title>Lectura de atributos específicos utilizando la API de Reflection</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>Declaración de clases de atributos</title>
|
|
|
|
<para>
|
|
Se recomienda definir una clase separada para cada atributo. En el caso más simple,
|
|
una clase vacía con la declaración <literal>#[Attribute]</literal> es suficiente.
|
|
El atributo puede ser importado desde el espacio de nombres global utilizando una declaración
|
|
<literal>use</literal>.
|
|
</para>
|
|
|
|
<example>
|
|
<title>Clase de atributo simple</title>
|
|
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
namespace Example;
|
|
|
|
use Attribute;
|
|
|
|
#[Attribute]
|
|
class MyAttribute
|
|
{
|
|
}
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
|
|
<para>
|
|
Para restringir los tipos de declaraciones a los que se puede aplicar un atributo,
|
|
pasa una máscara de bits como primer argumento en la declaración
|
|
<literal>#[Attribute]</literal>
|
|
</para>
|
|
|
|
<example>
|
|
<title>Usar la especificación de destino para restringir dónde se pueden usar los atributos</title>
|
|
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
namespace Example;
|
|
|
|
use Attribute;
|
|
|
|
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
|
|
class MyAttribute
|
|
{
|
|
}
|
|
]]>
|
|
</programlisting>
|
|
|
|
<para>
|
|
Declarar <classname>MyAttribute</classname> en otro tipo ahora generará una excepción durante
|
|
la llamada a <function>ReflectionAttribute::newInstance</function>
|
|
</para>
|
|
</example>
|
|
|
|
<para>Los siguientes destinos se pueden especificar:</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>
|
|
Por defecto, un atributo solo se puede usar una vez por declaración. Para permitir
|
|
que un atributo sea repetible, especifícalo en la máscara de bits de la
|
|
declaración <literal>#[Attribute]</literal> utilizando el
|
|
flag <constant>Attribute::IS_REPEATABLE</constant>
|
|
</para>
|
|
|
|
<example>
|
|
<title>Usar IS_REPEATABLE para permitir que un atributo se use varias veces en una declaración</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
|
|
-->
|