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

发布于 2024-12-10 12:52:50 字数 1694 浏览 1 评论 0原文

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

例如:

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 as ($args[0]), $required as ($args[1]) 等。另外,强制执行“正确”的参数。

我为什么要找这个?

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

借助此功能,我可以使用 __call()__get()__callStatic() 进行三种不同的自动加载。例如:

  1. __call()/includes/libraries 中查找
  2. __get() 查找插件/application/plugins
  3. __callStatic() 中查找,嗯,cats/application/cats 中>

如果有更好的办法自动加载,请分享。但如果可能的话,我仍在寻找这样的解决方案。也许使用 Reflection 类?

ReflectionClass 的一些工作示例:

$instance = new ReflectionClass($name);
$instance->newInstanceArgs($arguments);
return $instance;

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

注意:

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

I'm looking for a solution on how to use argument list for instantiating class' dynamically.

For example:

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;

As comment states, that results in error, but I'm looking to be able to access $object as ($args[0]), $required as ($args[1]) etc. Plus, enforce "correct" arguments.

Why am I looking for this?

The __autoload functionality of PHP is limited. Well, maybe it's not, but I have not found an easy way to differentiate class autoloads.

With this functionality, I can use __call(), __get(), __callStatic() for three different autoloads. Like:

  1. __call() looks for libraries in /includes/libraries
  2. __get() looks for plugins in /application/plugins
  3. __callStatic() looks for, umm, cats in /application/cats

If there is a better way through autoloading, please share. But I'm still looking for such a solution, if it's possible. Maybe with Reflection classes?

Somewhat working example with ReflectionClass:

$instance = new ReflectionClass($name);
$instance->newInstanceArgs($arguments);
return $instance;

But it's obvious here, that it will call ReflectionClass->__toString() here. Plus, overlooking the returned dump, it actually does not use the newInstanceArgs() here.

Notes:

I'm interested in example working prior to PHP 5.3.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

旧时模样 2024-12-17 12:52:50

使用反射:

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) {
}

Use reflection:

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

it takes an array just like call_user_func_array

Edit: a working example: 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) {
}
[浮城] 2024-12-17 12:52:50

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

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

// includes/libraries/Library/Foo.php

namespace Library;

class Foo {
    // ...
}

// application/plugins/Plugin/Bar.php

namespace Plugin;

class Bar {
    // ...
}

使用类似 Symfony 的通用类加载器

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;

There is a better way through autoloading.

Namespace your code, ie create "Library", "Plugin" and "Cats" namespaces in the relevant directories. For example

// includes/libraries/Library/Foo.php

namespace Library;

class Foo {
    // ...
}

// application/plugins/Plugin/Bar.php

namespace Plugin;

class Bar {
    // ...
}

Use something like 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;
朱染 2024-12-17 12:52:50

所以,这是一个工作示例,源自@Dani 的答案。

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

工作起来就像一个魅力,除了,我还不知道性能。

So, a working example, derived from @Dani's answer.

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

Works like a charm, except, I have no idea about performance yet.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文