Я узнал о mixins.So мое сомнение в том, можно ли использовать mixins в php? Если да, то как?
Использовать Trait
введенную в PHP 5.4.
<?php class Base { public function sayHello() { echo 'Hello '; } } trait SayWorld { public function sayHello() { parent::sayHello(); echo 'World!'; } } class MyHelloWorld extends Base { use SayWorld; } $o = new MyHelloWorld(); $o->sayHello(); ?>
который печатает Hello World!
Этот ответ устарел как PHP 5.4. См. Ответ Jeanno о том, как использовать черты .
Это действительно зависит от того, какой уровень mixins
вы хотите от PHP. PHP обрабатывает однонаправленное и абстрактное классы, которые могут помочь вам в большей части пути.
Конечно, лучшая часть миксинов заключается в том, что они взаимозаменяемые фрагменты, добавленные в любой класс, который им нужен.
Чтобы обойти проблему множественного наследования, вы можете использовать include
для вывода фрагментов кода. Вероятно, вам придется сбрасывать какой-то шаблонный код, чтобы заставить его работать должным образом в некоторых случаях, но это, безусловно, поможет сохранить ваши программы DRY.
Пример:
class Foo { public function bar( $baz ) { include('mixins/bar'); return $result; } } class Fizz { public function bar( $baz ) { include('mixins/bar'); return $result; } }
вclass Foo { public function bar( $baz ) { include('mixins/bar'); return $result; } } class Fizz { public function bar( $baz ) { include('mixins/bar'); return $result; } }
вclass Foo { public function bar( $baz ) { include('mixins/bar'); return $result; } } class Fizz { public function bar( $baz ) { include('mixins/bar'); return $result; } }
Это не так прямо, как возможность определить класс как class Foo mixin Bar
, но он должен получить от вас большую часть пути. Есть некоторые недостатки: вам нужно сохранить те же имена параметров и имена возвращаемых переменных, вам нужно передать другие данные, которые зависят от контекста, такого как func_get_args_array
или __FILE__
.
Mixins для PHP (PHP не реализует Mixins изначально, но эта библиотека поможет)
Первый результат google для «php5 mixin»: http://www.sitepoint.com/forums/php-application-design-147/ruby-like-mixins-php5-332491.html
Первый результат Google для «php mixin»: http://www.advogato.org/article/470.html
Короткий ответ: да, но не изначально (все же, очевидно, как отмечает @mchl). Проверьте их.
Более длинный ответ: если вы используете runkit , runkit_method_copy()
: «Копирует метод из класса в другой».
Я основывал функции mixins на записи в блоге, найденной в jansch.nl .
class Node { protected $__decorator_lookup = array(); public function __construct($classes = array()) { foreach($classes as $class) if (class_exists($class)) { $decorator = new $class($this); $methods = get_class_methods($decorator); if (is_array($methods)) foreach($methods as $method) $this->__decorator_lookup[strtolower($method)] = $decorator; } else trigger_error("Tried to inherit non-existant class", E_USER_ERROR); } public function __get($name) { switch($name) { default: if ($this->__decorator_lookup[strtolower($name)]) return $this->__call($name); } } public function __call($method, $args = array()) { if(isset($this->__decorator_lookup[strtolower($method)])) return call_user_func_array(array($this->__decorator_lookup[strtolower($method)], $method), $args); else trigger_error("Call to undefined method " . get_class($this) . "::$method()", E_USER_ERROR); } public function __clone() { $temp = $this->decorators; $this->decorators = array(); foreach($temp as $decorator) { $new = clone($decorator); $new->__self = $this; $this->decorators[] = $new; } } } class Decorator { public $__self; public function __construct($__self) { $this->__self = $__self; } public function &__get($key) { return $this->__self->$key; } public function __call($method, $arguments) { return call_user_func_array(array($this->__self, $method), $arguments); } public function __set($key, $value) { $this->__self->$key = $value; } } class Pretty extends Decorator { public function A() { echo "a"; } public function B() { $this->b = "b"; } } $a = new Node(array("Pretty")); $a->A(); // outputs "a" $a->B(); echo($a->b); // outputs "b"
РЕДАКТИРОВАТЬ:
unset($this->__self->someValue);
не будет отменять значение на Node
. Не знаю, почему, поскольку теоретически это должно работать. Забавно достаточно unset($this->__self->someValue); var_dump(isset($this->__self->someValue));
unset($this->__self->someValue); var_dump(isset($this->__self->someValue));
будет выдавать правильно false
, однако доступ к значению из области Node
(как Node->someValue
) будет по-прежнему выдавать true
. Там какой-то странный вуду.