Две недели не писал, а пиздюлей мне никто так и не дал. Ну ладно, вот, допустим, трейты. Вещь вполне себе, как оказывается, терпимая.
Вообще, все нововведения в PHP неизменно радуют. Нужно только отвлечься от того, что все они сделаны через жопу.
Теоретики плачут, что Traits, это никакое тебе не множественное наследование в высоком понимании этого термина. А самый, что ни на есть, банальный автоматизированный копипаст.
Однако, если посмотреть на языки с нормальным множественным наследованием, оно всё равно там в большинстве случаев используется именно для копипаста. Да и вообще, чуть ли не вся история развития программирования, это история автоматизации копипаста.
Вот, допустим, я люблю такое извращение:
namespace Module; /** * @property-read \Module\OneService $one * @property-read \Module\TwoService $two */ class Module extends \BaseModule { public function moduleMethod() { // ... } public function __get($key) { return $this->getService($key); } private function getService($key) { if (!\array_key_exists($key, $this->services)) { throw new \RuntimeException('Service "'.$key.'" is not found in Module'); } $service = $this->services[$key]; if (!\is_object($service)) { $service = new $service($this); $this->services[$key] = $service; } return $service; } private $services = array( 'one' => 'Module\OneService', 'two' => 'Module\TwoService', ); } |
То есть, в системе существуют некие модули в виде объектов, в них есть вложенные сервисы, к которым можно обращаться, как к полям модуля-агрегатора:
$system->moduleOne->serviceTwo->subserviceThree->method(); |
А список вложенных сервисов просто прописывается в отдельной переменной в виде «ключ» => «имя класса». При запросе создаётся объект и в том же массиве кэшируется.
Копипастить подобное надоедает, а базовый класс не сделать, так как все наши модули-агрегаторы могут наследоваться откуда угодно.
А с трейтами всё заебок:
trait SubservicesAggregator { public function __get($key) { return $this->getService($key); } private function getService($key) { if (!\array_key_exists($key, $this->services)) { throw new \RuntimeException('Service "'.$key.'" is not found in Module'); } $service = $this->services[$key]; if (!\is_object($service)) { $service = new $service($this); $this->services[$key] = $service; } return $service; } } |
namespace Module; /** * @property-read \Module\OneService $one * @property-read \Module\TwoService $two */ class Module extends \BaseModule { use \SubservicesAggregator; public function moduleMethod() { // ... } private $services = array( 'one' => 'Module\OneService', 'two' => 'Module\TwoService', ); } |
Ну, вернее, как всегда, не всё заебок. Например, нельзя сделать так:
/** * ... * @property-read string $three */ class Module extends \BaseModule { use \SubservicesAggregator; /** * __get() не только выдаёт вложенные сервисы, но и определяет какие-то дополнительные поля. */ public function __get($key) { if ($key == 'three') { return 'three'; } return parent::__get($key); // Не нашли специфического поля - передаём управление СервисАгрегатору } } |
Так не пойдёт, потому что parent
, это BaseModule
, а не SubserviceAggragator
.
Либо так делать:
use \SubservicesAggregator { __get as getSubservicesAggregator; } public function __get($key) { if ($key === 'three') { return '1'; } return $this->getSubservicesAggregator($key); } |
Либо, в нашем случае, просто:
public function __get($key) { if ($key === 'three') { return '1'; } return $this->getService($key); } |
Обратите внимание, что здесь мы вызываем getService()
, которые в трейте определён, как private
. Всё потому, что это ни разу не наследование, а просто копипаст.
В этом примере мы никак не изменили внешних интерфейсов, а только повторно использовали механизмы внутренней реализации. И незачем нам тут множественное наследование.
Как всегда, после PHP мы остаёмся с чувством полного удовлетворения и лёгкого омерзения. До новых встреч!
Спасибо, теперь я хоть узнал что это такое
adw0rd, 20.02.2013, 10:05
Тебе то зачем?
vasa_c, 20.02.2013, 13:06
Да заявляли что в 5.4 это появилось и это одна из крутых фич, может я путаю чего. Было интересно. Действительно полезная штука
adw0rd, 20.02.2013, 13:24
Ну пользоваться я точно не буду, но учту что это есть в PHP
adw0rd, 20.02.2013, 13:25