2017-05-15 12 views
1

クラスに関数を追加したかったので、これらの関数は別々のファイルにあり、それらの関数には($ this)が含まれています。クラスに非正則な関数を追加しないでください

class myClass { 
    private $myFunctions=array(); // will contain two keys (title, function_object) 
    private $var; 

    public function __construct() { 
     $this->var = 'Hello world'; 
    } 

    public function add_function($title, $func) { 
     $this->myFunctions[$title] = $func; 
    } 

} 

function add($x, $y) { 
    echo $this->var; 
    return $x + $y; 
} 

$class = new myClass; 
$class->add_function('add', 'add()'); 

echo $class->add(1,2); 

私の目標は、クラスに定期的な機能(ない無名関数)を追加したり、クラスに渡すことができるVARにそれらの機能(複数可)を割り当てることです!

これを達成できますか?

答えて

3

あなたはここのoopsの概念を理解する必要があります。

$これはあなたの現在のクラス/オブジェクトを参照しています。したがって、クラス内のすべての関数は$ this(現在のオブジェクト)にアクセスできます。

しかし、クラスの外に宣言された関数は、そのオブジェクトの$ thisを使用できません。 (ここまでは明確です)

しかし、とにかく何も不可能です。

少なくとも2つの方法で目標を達成できます。

2)特性を使用して複数の継承を実装できます。

それがこの

trait commonFunctions 
{ 

    function add($a, $b) 
    { 
     $this->result = $a + $b; 

     return $this; 
    } 
} 

class myClass 
{ 

    use commonFunctions; 

    public function myClassFunction() 
    { 
     // 
    } 
} 

2のようになります)それとも、コードの下に従うことができます。ソースphp.net

<?php 

class A { 
    function __construct($val) { 
     $this->val = $val; 
    } 
    function getClosure() { 
     //returns closure bound to this object and scope 
     return function() { return $this->val; }; 
    } 
} 

$ob1 = new A(1); 
$ob2 = new A(2); 

$cl = $ob1->getClosure(); 
echo $cl(), "\n"; 
$cl = $cl->bindTo($ob2); 
echo $cl(), "\n"; 

ここで__callは、宣言されていないメソッドが呼び出されるときに呼び出されます。このようにして、クラスにメソッドを動的に追加することができます。

もちろん、javascriptのようにオブジェクトをポリフィルすることができます。しかし、これをClosureにバインドするには、Reflectionを使用する必要があることに注意してください。

<?php 

class A { 

    private $dynamic_functions=[]; 

    public function __call($method, $args=[]) 
    { 
     if(isset($this->dynamic_functions[$method]) && $this->dynamic_functions[$method] instanceof \Closure) 
     { 
      $cl = $this->dynamic_functions[$method]->bindTo($this); 

      return call_user_func_array($cl, $args); 
     } 
     else 
     { 
      die("Wrong method, Not yet polyfilled."); 
     } 
    } 

    public function __set($property, $value) 
    { 
     $this->dynamic_functions[$property] = $value; 
    } 
} 

$a = new A; 

$a->sum = function($a,$b){ 

    // var_dump($this); will give you current instance of A 

    return $a+$b; 
}; 

echo $a->sum(5, 3); 
+0

ありがとう@PratikSoni無名関数は私の意図ではありません。特性を使用している はちょっと問題を複雑にしています。 – meYnot

0

いいえ、このようなクラスに関数を追加することはできません。この関数を持つ他のクラスでクラスを拡張することができます(add())。このように継承されたクラスは、親の関数add()を持ちます。

+1

形質を使用することができます。 –

2

可能ですが、その制限があります。オブジェクトの未定義のメソッドを呼び出す場合、magic method__callという名前のPHPチェックがある場合:

public mixed __call (string $name , array $arguments) 

この関数は、関数名、引数のリストを受け取ります。あなたの建設のために使用できる

public function __call($name, $args) { 
    // invokes the function with all arguments: 
    // e.g: function_name($arg[0], $arg[1], ...) 
    return call_user_func_array($this->myFunctions[$name], $args); 
} 

あなたの匿名機能の中で$ thisを使うことはできません。 Pythonでは、この問題は最初の引数(通常はselfと呼ばれています)としてインスタンスを渡すことで解決しました。私たちは、引数リストにインスタンスを追加することにより、同様のものを構築することができます:あなたはすでに最初の引数として$instanceを持っていないいくつかの機能を持っている場合は

public function __call($name, $args) { 
    // we add the instance at the beginning of the argument list 
    array_unshift($args, $this); 
    return call_user_func_array($this->myFunctions[$name], $args); 
} 

今、あなたは

function bork($instance, $a, $b) { 
    return $a*$b; 
} 
$class = new myClass; 
$class->add_function('derp', 'bork'); 
$class->add_function('add', function($instance, $x, $y) { 
    echo $instance->var; 
    return $x + $y; 
}); 

echo $class->derp(1,2); 
echo $class->add(35,34534); 

ような何かを行うことができ、あなたはそれをラップすることができます

function my_cool_existing_function($bla) { 
    echo $bla.$bla; 
} 
$class->add_function('super_bork', function($instance, $bla) { 
    return my_cool_existing_function($bla); 
}); 
+0

$ thisをクロージャーにバインドして同時に呼び出すことはできません。 –

+0

この文脈で「バインド」とはどういう意味ですか? PHPを – keksnicoh

+0

+1にバインドできないので、インスタンスを引数として渡します。はい、それは完璧ですが、$を使うとこれはできません。それは私が言ったことです。オブジェクトを渡すことができます。あなたはクロージャーから現在のスコープに通信するためのリファレンスを渡すことができました。 –

関連する問題