【问题标题】:Is it possible to use mixins in php是否可以在php中使用mixins
【发布时间】:2011-10-16 03:45:25
【问题描述】:

我开始了解 mixins。所以我的疑问是,是否可以在 php 中使用 mixins?如果可以,那么如何使用?

【问题讨论】:

  • PHP 5.4 将引入 Traits(在许多方面与 Mixins 一样好)

标签: php mixins


【解决方案1】:

从 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 and traits
  • 查看this answer 了解特征
【解决方案2】:

使用 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!

http://php.net/manual/en/language.oop5.traits.php

【讨论】:

    【解决方案3】:

    我基于 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"
    

    编辑:

    1. 由于 PHP 克隆很浅,添加了 __clone 支持。
    2. 另外,请记住,在 mixin 中未设置不会起作用(或者至少我没有设法使它起作用)。所以 - 做类似unset($this-&gt;__self-&gt;someValue); 的事情不会取消设置Node 的值。不知道为什么,理论上它应该可以工作。有趣的是unset($this-&gt;__self-&gt;someValue); var_dump(isset($this-&gt;__self-&gt;someValue)); 将正确生成false,但是从Node 范围访问值(如Node-&gt;someValue)仍然会生成true。那里有一些奇怪的巫术。

    【讨论】:

      【解决方案4】:

      “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():“将方法从类复制到另一个。”

      【讨论】:

      • 看到第一个谷歌结果落在这篇文章中会很有趣。如果有人指向另一个谷歌结果,它会导致stackoverflow吗?开始!
      • Virtual -1:对于“php5 mixin”和“php mixin”,我得到了一个完全不同的站点。看起来你的答案已经烂透了。
      【解决方案5】:

      Mixins for PHP(PHP 本身没有实现 Mixins,但是这个库会有所帮助)

      【讨论】:

      • 下面有一些有趣的 cmets。更不用说为什么幸运的僵硬是作者。
      猜你喜欢
      • 2010-09-20
      • 1970-01-01
      • 1970-01-01
      • 2011-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多