【发布时间】:2011-10-16 03:45:25
【问题描述】:
我开始了解 mixins。所以我的疑问是,是否可以在 php 中使用 mixins?如果可以,那么如何使用?
【问题讨论】:
-
PHP 5.4 将引入 Traits(在许多方面与 Mixins 一样好)
我开始了解 mixins。所以我的疑问是,是否可以在 php 中使用 mixins?如果可以,那么如何使用?
【问题讨论】:
从 PHP 5.4 起,此答案已过时。 See Jeanno's answer for how to use traits.
这真的取决于你想从 PHP 中获得什么级别的mixins。 PHP 处理单继承和抽象类,这可以帮助您完成大部分工作。
当然,mixin 最好的部分是它们是可互换的 sn-ps,可以添加到任何需要它们的类中。
要解决多重继承问题,您可以使用include 拉入sn-ps 代码。在某些情况下,您可能必须转储一些样板代码才能使其正常工作,但这肯定有助于保持程序 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__。
【讨论】:
使用 PHP 5.4 中引入的Trait
<?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!
【讨论】:
我基于 jansch.nl 上的博客条目创建了 mixins 功能。
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)); 将正确生成false,但是从Node 范围访问值(如Node->someValue)仍然会生成true。那里有一些奇怪的巫术。【讨论】:
“php5 mixin”的第一个谷歌结果:http://www.sitepoint.com/forums/php-application-design-147/ruby-like-mixins-php5-332491.html
“php mixin”的第一个谷歌结果:http://www.advogato.org/article/470.html
简短回答:是的,但不是本地的(但显然,正如@mchl 所指出的那样)。看看这些。
更长的答案:如果您使用的是runkit,请查看runkit_method_copy():“将方法从类复制到另一个。”
【讨论】:
Mixins for PHP(PHP 本身没有实现 Mixins,但是这个库会有所帮助)
【讨论】: