魔术方法__call()参数为“真实”参数

时间:2011-10-18 23:03:32

标签: php oop

我正在寻找一个关于如何使用参数列表动态实例化类的解决方案。

例如:

class test {

    public function __call($name, $args){
        /* blah, blah class exists? require */
        return new $name($args);
    }

    public function __toString(){
        return (string) $this->extension(); // to enforce __toString of extension
    }
}

class extension extends test {
    public function __construct(classTypeHint $object, $required, $random = 25){
        // This does not work, results in:
        // "Argument 1 passed to extension::__construct must be an instance of classTypeHint, array given...
    }

    public function __toString(){
        return var_export($this, true);
    }
}

echo new test;

正如评论所述,这会导致错误,但我希望能够访问$object$args[0]),$必需为($args[1])等。另外,强制执行“正确”的论点。

我为什么要找这个?

PHP的__autoload功能有限。好吧,也许不是,但我还没有找到一种简单的方法来区分类自动加载。

借助此功能,我可以将__call()__get()__callStatic()用于三种不同的自动加载。像:

  1. __call()/includes/libraries
  2. 中查找 libraries
  3. __get()/application/plugins
  4. 中查找插件
  5. __callStatic()在[{1}}
  6. 中查找,嗯,

    如果有更好的自动加载方式,请分享。但如果可能的话,我仍在寻找这样的解决方案。也许是/application/cats班?

    使用ReflectionClass的一些工作示例:

    Reflection

    但是这里很明显,它会在这里调用ReflectionClass-> __ toString()。另外,忽略返回的转储,它实际上并没有在这里使用newInstanceArgs()。

    注意:

    我对PHP 5.3之前的示例感兴趣。

3 个答案:

答案 0 :(得分:4)

使用反射:

public function __call($name, $args)
{
    return (new ReflectionClass($name))->newInstanceArgs($args);
}

它需要一个像call_user_func_array

一样的数组

编辑:一个有效的例子:http://codepad.org/ZZpBwRij

<?php

class MyClass
{
    public function __construct($a, $b)
    {
        echo "__construct($a, $b) called";
    }
}

function create($name, $args)
{
    $class = new ReflectionClass($name);
    return $class->newInstanceArgs($args);
}

var_dump(create('MyClass', array(1, 2)));

?>

Output:

__construct(1, 2) called
object(MyClass)#2 (0) {
}

答案 1 :(得分:1)

通过自动加载有更好的方法。

命名空间代码,即在相关目录中创建“Library”,“Plugin”和“Cats”命名空间。例如

// includes/libraries/Library/Foo.php

namespace Library;

class Foo {
    // ...
}

// application/plugins/Plugin/Bar.php

namespace Plugin;

class Bar {
    // ...
}

使用Symfony's universal class loader

之类的内容
require_once 'path/to/Symfony/Component/ClassLoader/UniversalClassLoader.php';

$loader = new \Symfony\Component\ClassLoader\UniversalClassLoader;
$loader->registerNamespaces(array(
    'Library' => 'path/to/includes/libraries',
    'Plugin'  => 'path/to/application/plugins'
));
$loader->register();

$foo = new \Library\Foo;
$bar = new \Plugin\Bar;

答案 2 :(得分:0)

所以,一个工作的例子,源于@ Dani的答案。

public function __call($name, $args){
    $reflection = new ReflectionClass($name);
    return $reflection->newInstanceArgs($args);
}

像魅力一样,除了,我还不知道表现。