PHP Черты общих и индивидуальных (отдельных) свойств области - PullRequest
1 голос
/ 24 января 2020

Полезно, чтобы методы, определенные внутри признаков, имели доступ к общему объему свойств, например, методы, определенные в одном и том же объекте. Однако есть ли способ, чтобы две черты могли использовать одно и то же имя свойства, но каждое свойство было бы в другой области видимости, поэтому setTwo() не будет перезаписывать $this->data из trait one и наоборот?

пример:

<?php

namespace one;

trait one {

    public function setOne($data) {
        $this->data = $data;
    }

    public function getOne()
    {
        return $this->data;
    }
}

namespace two;

trait two {

    public function setTwo($data) {
        $this->data = $data;
    }

    public function getTwo()
    {
        return $this->data;
    }
}

namespace bar;

class Bar {
    use \one\one;
    use \two\two;
}

$bar = new Bar;

$bar->setOne(1);
$bar->setTwo(2);

echo "Bar getOne: " . $bar->getOne() . '<br>' . PHP_EOL; // echoes 2 instead of wanted 1
echo "Bar getTwo: " . $bar->getTwo() . '<br>' . PHP_EOL; // overwrites $this->data = 1 with 2
echo "Bar->data: " . $bar->data . '<br>' .  PHP_EOL;

Причина, по которой я ищу отдельную область видимости, заключается в том, что для имен общих свойств, таких как: сумма, результат, кэш, в какой-то момент вы можете непреднамеренно перезаписать их при составлении класса из многих черт.

Единственное, что мне приходит в голову, - это использовать промежуточный класс (который имеет собственное пространство имен и, следовательно, свою собственную область видимости), составленный из черт, и передать его как зависимость другому классу, который нуждается некоторые функции черт, используемых для промежуточного состава. В приведенном выше примере мне понадобятся два промежуточных класса - один с чертой один, другой с чертой два.

Есть ли другие варианты, кроме промежуточного класса или изменения в каждой черте $this->data на более специальные имена типа $this->dataOne и $this->dataTwo?

1 Ответ

1 голос
/ 24 января 2020

Каждая черта должна определять свойства, которые нужны ее методам.

Использование неопределенных свойств или свойств, определенных в классе, который использует черты для композиции, является плохой идеей. Следовательно, наличие нескольких черт, которые зависят от одних и тех же свойств, является также плохой идеей.

Каждая черта должна обеспечивать все, что ей нужно для работы, логика c мудро.

Кроме того, черты не имеют «объема». При использовании признаков характерно, как если бы код в признаке копировался в класс потребления. В вашем примере область действия setOne() и getTwo() является экземпляром Bar, что методы, определенные в чертах, не имеют значения.

Более разумный способ сделать это - включить любые свойства вашей черты потребность в самой черте:

Например:

 trait CanLog {

    private LoggerInterface $logger;

    public function error(string $data)
    {
        $this->logger->error($data);
    }

    public function alert(string $data)
    {
        $this->logger->error($data);
    }
}

Таким образом, класс потребления просто импортирует требуемое поведение из черты, завершает и может вставлять все, что им нужно, в свойствах, которые черта обеспечивает:

class Bar
{
    use CanLog;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger; 
    }
}
...