Mixins in PHP

Комментарии к статье
«Mixins in PHP»

Не буду распространяться, что такое Mixins — об этом уже много и восторженно написано. Проблема в том, что PHP напрямую не поддерживает примеси, но есть несколько способов решения задачи. Те, что находятся в интернете используют eval... Мы пойдем иным путем. Есть ведь магические методы типа __call(), __get() и __set()


***

Вот немного переделал под php 5.3
теперь можно вызывать статические методы подмешиваемого класса.

<?php

abstract class Mixin {
private $clr;

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

public function __get($prop) {
return $this->clr->__access_get_prop($prop);
}


public function __set($prop, $value) {
return $this->clr->__access_set_prop($prop, $value);
}


public function __call($method, $args) {
return $this->clr->__access_call($method, $args);
}
}

abstract class Caller {
private $mixins = array(); // массив экземпляров примсей

public function __call($method, $args) {
foreach ($this->mixins as $cname => $co) {
if (method_exists($co, $method)) {
return call_user_func_array(array($co, $method), $args);
}
}
throw new Exception("call to unfdefined method " . $method);
}

public static function __callStatic($method, $args){
if (isset(static::$mixins)){
foreach (static::$mixins as $cname) {
if (method_exists($cname, $method)) {
return call_user_func_array(array($cname, $method), $args);
}
}
}
throw new Exception("call to unfdefined static method " . $method);
}

public function __access_get_prop($prop) {
if (property_exists($this, $prop)) {
return $this->$prop;
}
}

public function __access_set_prop($prop, $value) {
if (property_exists($this, $prop)) {
return $this->$prop = $value;
}
}

public function __access_call($method, $args) {
if (method_exists($this, $method)) {
return call_user_func_array(array($this, $method), $args);
}
}

public function mixin($classes){
if (!is_array($classes)) $classes = array($classes);
foreach ($classes as $class){
$this->mixins[$class] = new $class($this);
}
}
}


/*
* использование
*/

// конкретная примесь с присущим ей функционалом
class SayHello extends Mixin {
public function say() {
return "Hello " . $this->name;
}

public function sayLoud() {
return 'Hello ' . $this->loud() . '!!!';
}

public function addPrefix() {
$this->name = "Mr. " . $this->name;
}

public static function testStatic(){
return '<p>это статик функция</p>';
}
}

// конкретный родительский класс, расширенный примесью
class Person extends Caller {
static $mixins = array('SayHello');
public $name;

function __construct($name) {
$this->name = $name;
$this->mixin('SayHello');
}

public function loud() {
return '<b>' . $this->name . '</b>';
}

public function saySomething() {
$this->addPrefix();
return '<h2>' . $this->name . '</h2>';
}

}

$p = new Person("Schleicher");

echo $p->say(); // Hello Schleicher
echo $p->sayLoud(); // Hello <b>Schleicher</b>!!!
echo $p->saySomething(); // <h2>Mr. Schleicher</h2>
echo $p->testStatic();

Михаил (2.05.2010)

Реализовал свою небольшую библиотеку для примесей. Быстродействие, в принципе, приемлемое:

http://ru.fractalizer.ru/frpost_128/

FractalizeR (7.11.2010)

Отличная модель, спасибо! Я написал точно такую же модель (после знакомства с примесями в википедии), только без __access_get/set_prop (спасибо за подсказку).

Но, меня очень интересует именно целесообразность использования примесей. Можно ведь с помощью делегирования добиться такого же code reuse (не совсем прям такого же, но более нативного и прозрачного). Mixins выглядят более логично, а делегирование - проще и безопаснее.
Подскажите Ваше мнение по этой дилемме, пожалуйста.

OZ (11.11.2010)

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

schleicher (11.11.2010)

Отсутствие грамотно оформленного кода говорит нам о пренебрежительном отношении автора к материалу и читателям

Блабла (13.11.2010)

Отлично! Спасибо, действительно очень просто и доступно.
зы: Блабла, ваш пост говорит о том, что вы зря зашли на эту страницу.

Alex-an (13.11.2010)

Check out ClassMixer: https://github.com/wellsprin...dwide/PHP-ClassMixer

Anthony (16.12.2010)

Thank you for this. I was on the right track but got stuck when it came to access private and protected methods from within the mixin class. Searched for hours but thankfuly found this code.

Kudos.

buggedcom (23.02.2012)

Спасибо.
Вы хорошо объясняете.
Столкнулся с этим шаблоном в Yii не мог понять что к чему.
Теперь ясно.

Михаил (5.02.2013)

добавить комментарий
Имя
e-mail
URL
Комментарий
Самизнаетечто

mem: 1207 total: 30 module: 14 xsl: 13