Skip to content

Instantly share code, notes, and snippets.

@monmonmon
Last active September 21, 2020 10:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monmonmon/6922871 to your computer and use it in GitHub Desktop.
Save monmonmon/6922871 to your computer and use it in GitHub Desktop.
Trait が導入される php5.4 より前の php で mixin 的なことを実装してみた。
<?php
// mixin クラス
class MixinClass
{
// インスタンスメソッド(引数あり)
//  注:第1引数に、mixin 先のクラスのインスタンスを表す "$that" が必要です。
//  実際呼ぶ時は ->mixin_instance_method($message) ってなります。
public function mixin_instance_method($that, $message, DateTime $date)
{
print "これは MixinClass のインスタンスメソッドです $message ".$date->format('Y-m-d')."\n";
print "Foo の public メンバ変数にアクセスすることも出来ます。 ".$that->foooooo."\n";
}
// 静的メソッド(引数あり)
public static function mixin_static_method($message, DateTime $date)
{
print "これは MixinClass の静的メソッドです $message ".$date->format('Y-m-d')."\n";
}
}
// mixin クラスその2。mixin するクラスが複数になってもいけます
class MixinClass2
{
// インスタンスメソッド(引数なし)
//  注:引数なしのメソッドでも第1引数に "$that" は必要です。
//  実際呼ぶ時は ->mixin2_instance_method() こーなります。
public function mixin2_instance_method($that)
{
print "これは MixinClass2 のインスタンスメソッドです\n";
}
// 静的メソッド(引数なし)
public static function mixin2_static_method()
{
print "これは MixinClass2 の静的メソッドです\n";
}
}
// 親クラス
class Bar
{
// 親クラス Bar のインスタンスメソッド
public function parent_instance_method()
{
print "これは親クラス Bar のインスタンスメソッドです\n";
}
// 親クラス Bar の静的メソッド
public static function parent_static_method()
{
print "これは親クラス Bar の静的メソッドです\n";
}
}
// mixin 対象クラス
class Foo extends Bar
{
public $foooooo = 999;
// コンストラクタで MixinClass, MixinClass2 のインスタンスを作っときます
public function __construct()
{
$this->mixin1 = new MixinClass();
$this->mixin2 = new MixinClass2();
}
// __call をオーバーライドして、インスタンスメソッドの mixin を実装します
// インスタンスメソッド $method_name がこのクラスでも先祖クラスでも未定義な場合、ここへ到達。
public function __call($method_name, $args)
{
// Foo 自身を表す $this を引数の先頭に追加します
array_unshift($args, $this);
if (is_callable(array(&$this->mixin1, $method_name))) {
// MixinClass#$method_name を実行
return call_user_func_array(array(&$this->mixin1, $method_name), $args);
} elseif (is_callable(array(&$this->mixin2, $method_name))) {
// MixinClass2#$method_name を実行
return call_user_func_array(array(&$this->mixin2, $method_name), $args);
} else {
throw new BadMethodCallException();
}
}
// __callStatic (php5.3.0 以降) をオーバーライドして、静的メソッドの mixin を実装します
// 静的メソッド $method_name がこのクラスでも先祖クラスでも未定義な場合、ここへ到達。
public static function __callStatic($method_name, $args)
{
if (is_callable("MixinClass::$method_name")) {
// MixinClass::$method_name を実行
return call_user_func_array("MixinClass::$method_name", $args);
} elseif (is_callable("MixinClass2::$method_name")) {
// MixinClass2::$method_name を実行
return call_user_func_array("MixinClass2::$method_name", $args);
} else {
throw new BadMethodCallException();
}
}
// Foo 自身のインスタンスメソッド
public function instance_method()
{
print "これは Foo 自身のインスタンスメソッドです\n";
}
// Foo 自身の静的メソッド
public static function static_method()
{
print "これは Foo 自身の静的メソッドです\n";
}
}
// Foo クラスのインスタンスを生成
$foo = new Foo();
//--------------------------------------------------
// 1. まずはインスタンスメソッドの mixin を実験
// MixinClass から mixin された mixin_instance_method() を呼んでみる
print "// \$foo->mixin_instance_method\n";
$foo->mixin_instance_method("yahoooooo!", new DateTime());
print "\n";
// MixinClass2 から mixin された mixin2_instance_method() を呼んでみる
print "// \$foo->mixin2_instance_method\n";
$foo->mixin2_instance_method();
print "\n";
// Foo 自身のインスタンスメソッドを呼んでみる
print "// \$foo->instance_method\n";
$foo->instance_method();
print "\n";
// 親クラス Bar のインスタンスメソッドも呼んでみる
print "// \$foo->parent_instance_method\n";
$foo->parent_instance_method();
print "\n";
//--------------------------------------------------
// 2. 次に静的メソッドの mixin も実験
// MixinClass から mixin された mixin_static_method() を呼んでみる
print "// Foo::mixin_static_method\n";
Foo::mixin_static_method("yahoooooo!", new DateTime());
print "\n";
// MixinClass2 から mixin された mixin2_static_method() を呼んでみる
print "// Foo::mixin2_static_method\n";
Foo::mixin2_static_method();
print "\n";
// Foo 自身の静的メソッドを呼んでみる
print "// Foo::static_method\n";
Foo::static_method();
print "\n";
// 親クラス Bar の静的メソッドも呼んでみる
print "// Foo::parent_static_method\n";
Foo::parent_static_method();
print "\n";
//--------------------------------------------------
// 3. いいね!
print <<<IINE
     *      *
  *     +
     n ∧_∧ n  IINE!
 + (ヨ(* ´∀`)E)
      Y     Y    *
IINE;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment