private $_mixin_methods;
private $_mixin_classes;
public function mixin() {
$behaviors = func_get_args();
if ((count($behaviors) == 0) ||
!isset($this->_mixin_methods) ||
!isset($this->_mixin_classes)) {
$this->_mixin_methods = array();
$this->_mixin_classes = array();
}
foreach($behaviors as $b) {
list($c, $m) = explode('-', $b.'-');
if (empty($m)) {
list($c, $m) = explode('+', $b.'+');
$skip = false;
} else {
$skip = true;
}
$mfilter = empty($m) ? array() : explode(',', $m);
if(isset($this->_mixin_classes[$c])) {
foreach($this->_mixin_classes[$c] as $m) {
if ($this->_mixin_methods[$m] == $c) unset($this->_mixin_methods[$m]);
}
unset($this->_mixin_classes[$c]);
}
$methods = get_class_methods($c);
if (is_array($methods)) {
if (empty($mfilter)) {
foreach($methods as $m) {
$m = strtolower($m);
$this->_mixin_methods[$m] = $c;
$this->_mixin_classes[$c][] = $m;
}
} else {
foreach($methods as $m) {
$m = strtolower($m);
$matched = false;
foreach($mfilter as $wildcard) {
if (fnmatch($wildcard, $m, FNM_CASEFOLD)) {
$matched = true;
break;
}
}
if ($matched == $skip) continue;
$this->_mixin_methods[$m] = $c;
$this->_mixin_classes[$c][] = $m;
}
}
}
}
}
public function __call($method, $args) {
$m = strtolower($method);
if (isset($this->_mixin_methods[$m])) {
$class = $this->_mixin_methods[$m];
array_unshift($args, $this);
return call_user_func_array(array($class, $m), $args);
}
trigger_error('Call to undefined function '.$method, E_USER_ERROR);
}
}
用两段代码来说明用法:
例1:行为的继承
class Course {
public static function greeting($obj) {
if (get_class($obj) == 'Teacher')
echo "Good morning class!\n";
else
echo "Good morning teacher!\n";
}
}
class CourseWork extends Course {
public static function homeworkReview($obj) {
echo "I am reviewing homework...\n";
}
}
class HomeWork extends Course {
public static function homeworkStudy($obj) {
echo "I am doing my homework...\n";
}
}
class Teacher extends Mixable {
}
class Student extends Mixable {
}
$t = new Teacher();
$t->mixin('CourseWork');
$s = new Student();
$s->mixin('HomeWork');
$t->greeting();
$t->homeworkReview();
$s->greeting();
$s->homeworkStudy();
public static function greeting($obj) {
if (get_class($obj) == 'Teacher')
echo "Good morning class!\n";
else
echo "Good morning teacher!\n";
}
}
class CourseWork extends Course {
public static function homeworkReview($obj) {
echo "I am reviewing homework...\n";
}
}
class HomeWork extends Course {
public static function homeworkStudy($obj) {
echo "I am doing my homework...\n";
}
}
class Teacher extends Mixable {
}
class Student extends Mixable {
}
$t = new Teacher();
$t->mixin('CourseWork');
$s = new Student();
$s->mixin('HomeWork');
$t->greeting();
$t->homeworkReview();
$s->greeting();
$s->homeworkStudy();
在这个例子中,演示了行为是可以继承的。另外要注意,行为类中的方法一般需要写作static的,虽然不写成static也可以跑,但如果php设置为STRICT模式,会有告警。
例2:选择性注入
class Behavior {
public static function adminAction($obj) {
echo "> This behavior require <admin> privilege\n";
}
public static function userAction($obj) {
echo "> This behavior is normal\n";
}
}
class Power {
public static function hyperPower($obj) {
echo "> PHP Hyper Power...\n";
}
}
class Main extends Mixable {
}
$m = new Main();
echo "Mixin Behavior without exclusion\n";
$m->mixin('Behavior', 'Power');
echo "Trying user action\n";
$m->userAction();
echo "Trying admin action\n";
$m->adminAction();
$opt = mt_rand() % 3;
switch($opt) {
case 0:
echo "Mixin Behavior while excluding admin action\n";
$m->mixin('Behavior-Admin*');
break;
case 1:
echo "Mixin Behavior while including only user action\n";
$m->mixin('Behavior+User*');
break;
default:
echo "Mixin Behavior again (clearing Hyper Power)\n";
$m->mixin();
$m->mixin('Behavior');
}
echo "Trying hyper power...\n";
$m->hyperPower();
echo "Trying user action\n";
$m->userAction();
echo "Trying admin action\n";
$m->adminAction();
这个例子说明以下几个用法:
- 通过类名+方法1,方法2...(只注入这些方法)或者类名-方法1,方法2...(注入除这些方法以外的其它方法)这种表达法来选择性地注入行为类中的一部分方法
- 如果多次注入不同的行为,先前注入的不会被取消,除非以无参数的mixin()调用来清除以前注入的类
- 在过虑方法名的时候可以用shell通配符(大小写不区分)
- 最后(代码中没有体现),mixin()方法的参数可变。一次mixin调用可以注入多个类,例如: $obj->mixin('Class1', 'Class2');