PHP.mk документација

Преглед на атрибути

Почист и полокален преглед на PHP референцата, со задржана структура од PHP.net и подобра читливост за примери, секции и белешки.

language.attributes.overview.php PHP.net прокси Преводот се освежува
Оригинал на PHP.net
Патека language.attributes.overview.php Локална патека за оваа страница.
Извор php.net/manual/en Оригиналниот HTML се реупотребува и локално се стилизира.
Режим Прокси + превод во позадина Кодовите, табелите и белешките остануваат читливи во истиот тек.
Преглед на атрибути

Референца за `language.attributes.overview.php` со подобрена типографија и навигација.

language.attributes.overview.php

Преглед на атрибути

(PHP 8)

(PHP 8) PHP атрибутите обезбедуваат структурирани, машински читливи метаподатоци за класи, методи, функции, параметри, својства и константи. Тие можат да се инспектираат во време на извршување прекуReflection API

, што овозможува динамично однесување без менување на кодот. Атрибутите обезбедуваат декларативен начин за анотирање на кодот со метаподатоци.

Атрибутите овозможуваат одвојување на имплементацијата на една функција од нејзината употреба. Додека интерфејсите дефинираат структура со наметнување методи, атрибутите обезбедуваат метаподатоци низ повеќе елементи, вклучувајќи методи, функции, својства и константи. За разлика од интерфејсите, кои наметнуваат имплементации на методи, атрибутите го анотираат кодот без да ја менуваат неговата структура. ActionHandler Атрибутите можат да ги надополнат или заменат опционалните методи на интерфејсот со обезбедување метаподатоци наместо наметната структура. Разгледајте ActionHandler интерфејс што претставува операција во апликација. Некои имплементации може да бараат чекор за поставување, додека други не. Наместо да ги принудувате сите класи што го имплементираат setUp() да дефинираат

метод, атрибутот може да ги означи барањата за поставување. Овој пристап ја зголемува флексибилноста, дозволувајќи атрибутите да се применат повеќе пати кога е потребно.

<?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);

Белешки од корисници 3 белешки

Пример #1 Имплементирање опционални методи на интерфејс со атрибути
3 години пред
I've tried Harshdeeps example and it didn't run out of the box and I think it is not complete, so I wrote a complete and working naive example regarding attribute based serialization.

<?php
declare(strict_types=1);

#[Attribute(Attribute::TARGET_CLASS_CONSTANT|Attribute::TARGET_PROPERTY)]
class JsonSerialize
{
    public function __construct(public ?string $fieldName = null) {}
}

class VersionedObject
{
    #[JsonSerialize]
    public const version = '0.0.1';
}

class UserLandClass extends VersionedObject
{
    protected string $notSerialized = 'nope';

    #[JsonSerialize('foobar')]
    public string $myValue = '';

    #[JsonSerialize('companyName')]
    public string $company = '';

    #[JsonSerialize('userLandClass')]
    protected ?UserLandClass $test;

    public function __construct(?UserLandClass $userLandClass = null)
    {
        $this->test = $userLandClass;
    }
}

class AttributeBasedJsonSerializer {

    protected const ATTRIBUTE_NAME = 'JsonSerialize';

    public function serialize($object)
    {
        $data = $this->extract($object);

        return json_encode($data, JSON_THROW_ON_ERROR);
    }

    protected function reflectProperties(array $data, ReflectionClass $reflectionClass, object $object)
    {
        $reflectionProperties = $reflectionClass->getProperties();
        foreach ($reflectionProperties as $reflectionProperty) {
            $attributes = $reflectionProperty->getAttributes(static::ATTRIBUTE_NAME);
            foreach ($attributes as $attribute) {
                $instance = $attribute->newInstance();
                $name = $instance->fieldName ?? $reflectionProperty->getName();
                $value = $reflectionProperty->getValue($object);
                if (is_object($value)) {
                    $value = $this->extract($value);
                }
                $data[$name] = $value;
            }
        }

        return $data;
    }

    protected function reflectConstants(array $data, ReflectionClass $reflectionClass)
    {
        $reflectionConstants = $reflectionClass->getReflectionConstants();
        foreach ($reflectionConstants as $reflectionConstant) {
            $attributes = $reflectionConstant->getAttributes(static::ATTRIBUTE_NAME);
            foreach ($attributes as $attribute) {
                $instance = $attribute->newInstance();
                $name = $instance->fieldName ?? $reflectionConstant->getName();
                $value = $reflectionConstant->getValue();
                if (is_object($value)) {
                    $value = $this->extract($value);
                }
                $data[$name] = $value;
            }
        }

        return $data;
    }

    protected function extract(object $object)
    {
        $data = [];
        $reflectionClass = new ReflectionClass($object);
        $data = $this->reflectProperties($data, $reflectionClass, $object);
        $data = $this->reflectConstants($data, $reflectionClass);

        return $data;
    }
}

$userLandClass = new UserLandClass();
$userLandClass->company = 'some company name';
$userLandClass->myValue = 'my value';

$userLandClass2 = new UserLandClass($userLandClass);
$userLandClass2->company = 'second';
$userLandClass2->myValue = 'my second value';

$serializer = new AttributeBasedJsonSerializer();
$json = $serializer->serialize($userLandClass2);

var_dump(json_decode($json, true));
Florian Krmer
пред 4 години
While the example displays us what we can accomplish with attributes, it should be kept in mind that the main idea behind attributes is to attach static metadata to code (methods, properties, etc.). 

This metadata often includes concepts such as "markers" and "configuration". For example, you can write a serializer using reflection that only serializes marked properties (with optional configuration, such as field name in serialized file). This is reminiscent of serializers written for C# applications.

That said, full reflection and attributes go hand in hand. If your use case is satisfied by inheritance or interfaces, prefer that. The most common use case for attributes is when you have no prior information about the provided object/class.

<?php
interface JsonSerializable
{
    public function toJson() : array;
}
?>

versus, using attributes,
<?php

#[Attribute]
class JsonSerialize 
{
    public function __constructor(public ?string $fieldName = null) {}
}

class VersionedObject
{
   #[JsonSerialize]
    public const version = '0.0.1';
}

public class UserLandClass extends VersionedObject
{
    #[JsonSerialize('call it Jackson')]
    public string $myValue;
}

?>
The example above is a little extra convoluted with the existence of the VersionedObject class as I wished to display that with attribute mark ups, you do not need to care how the base class manages its attributes (no call to parent in overriden method).
Harshdeep
hello at tzi dot fr
It is possible to use self:: keyword in class-level attribute to reference current class, although it is actually placed "outside" class definition. Private constants also are visible. For example:

#[ApiResource(
    operations: [
        new Get(
            uriTemplate: '/{id}',
            normalizationContext: ['groups' => self::NORMALIZATION_GROUPS],
        ),
    ]
)]
#[ORM\Entity]
class MyEntity
{
    private const array NORMALIZATION_GROUPS = ['groups'];
    ...
}
На оваа страница

Автоматски outline од активната документација.

Насловите ќе се појават тука по вчитување.

Попрегледно читање

Примерите, changelog табелите и user notes се визуелно издвоени за да не се губат во долгата содржина.

Брз совет Користи го outline-от Скокни директно на главните секции од активната страница.
Извор Оригиналниот линк останува достапен Кога ти треба целосен upstream context, отвори го PHP.net во нов tab.