Я узнал о mixins.So мое сомнение есть, возможно ли использовать mixins в php? Если да, то как?
Можно ли использовать mixins в php
Ответ 1
Используйте 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!
Ответ 2
Этот ответ устарел как PHP 5.4. См. ответ Jeanno для использования признаков.
Это действительно зависит от уровня mixins
, который вы хотите от PHP. PHP обрабатывает однонаследование и абстрактные классы, которые могут помочь вам в основном.
Конечно, лучшая часть mixins - это взаимозаменяемые фрагменты, добавленные в любой класс, который им нужен.
Чтобы обойти проблему множественного наследования, вы можете использовать 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 mixin Bar
, но он должен получить от вас большую часть пути. Есть некоторые недостатки: вам нужно сохранить те же имена параметров и имена возвращаемых переменных, вам нужно передать другие данные, которые зависят от контекста, например func_get_args_array
или __FILE__
.
Ответ 3
Mixins for PHP (PHP не реализует Mixins изначально, но эта библиотека поможет)
Ответ 4
Первый результат 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, checkout runkit_method_copy()
: "Копирует метод из класса в другой".
Ответ 5
Я основывал функции 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"
ИЗМЕНИТЬ:
- Поскольку клон PHP неглубокий, добавлена поддержка __clone.
- Кроме того, помните, что unset НЕ будет работать (или, по крайней мере, мне не удалось заставить его работать) в mixin. Итак - выполнение чего-то вроде
unset($this->__self->someValue);
не будет отменять значение наNode
. Не знаю, почему, поскольку теоретически это должно работать. Достаточно смешноunset($this->__self->someValue); var_dump(isset($this->__self->someValue));
будет правильно отображатьfalse
, однако доступ к значению из областиNode
(какNode->someValue
) будет по-прежнему производитьtrue
. Там какой-то странный вуду.