草庐IT

php - 快速检查对象是否会在 PHP 中成功实例化?

coder 2024-04-15 原文

如何在不实际创建实例的情况下检查对象是否将使用给定参数成功实例化?

实际上我只是检查(没有测试这段代码,但应该可以正常工作...)必需参数的数量,忽略类型:

// Filter definition and arguments as per configuration
$filter = $container->getDefinition($serviceId);
$args   = $activeFilters[$filterName];

// Check number of required arguments vs arguments in config
$constructor = $reflector->getConstructor();

$numRequired  = $constructor->getNumberOfRequiredParameters();
$numSpecified = is_array($args) ? count($args) : 1;

if($numRequired < $numSpecified) {
    throw new InvalidFilterDefinitionException(
        $serviceId,
        $numRequired,
        $numSpecified
    );
}

编辑:$constructor 可以是null...

最佳答案

简短的回答是,您根本无法确定一组参数是否允许构造函数的无错误实例化。正如评论者在上面提到的,没有办法确定一个类是否可以用给定的参数列表实例化,因为如果不实际尝试就无法知道运行时的注意事项 实例化。

但是,尝试从构造函数参数列表中实例化一个类是有值(value)的。这种操作最明显的用例是可配置的依赖注入(inject)容器 (DIC)。不幸的是,这比 OP 建议的操作复杂得多。

我们需要为提供的定义数组中的每个参数确定它是否与构造方法签名中指定的类型提示匹配(如果方法签名实际上有类型提示)。此外,我们需要解决如何处理默认参数值的问题。此外,为了使我们的代码具有任何实际用途,我们需要允许提前指定“定义”以实例化一个类。对该问题的复杂处理还将涉及反射对象池(缓存),以最大限度地减少重复反射事物对性能的影响。

另一个障碍是,如果不调用其 ReflectionParameter::getClass 方法并随后从返回的类名实例化反射类,则无法访问反射方法参数的类型提示 (如果返回 null,则参数没有类型提示)。这就是缓存生成的反射对于任何现实世界的用例变得特别重要的地方。

下面的代码是我自己的基于字符串的递归依赖注入(inject)容器的精简版。它是伪代码和真实代码的混合体(如果您希望获得免费代码来复制/粘贴,那您就不走运了)。您会看到下面的代码将“定义”数组的关联数组键与构造函数签名中的参数名称相匹配。

真正的代码可以在相关的github project page找到.

class Provider {

    private $definitions;

    public function define($class, array $definition) {
        $class = strtolower($class);
        $this->definitions[$class] = $definition;
    }

    public function make($class, array $definition = null) {
        $class = strtolower($class);

        if (is_null($definition) && isset($this->definitions[$class])) {
            $definition = $this->definitions[$class];
        }

        $reflClass = new ReflectionClass($class);
        $instanceArgs = $this->buildNewInstanceArgs($reflClass);


        return $reflClass->newInstanceArgs($instanceArgs);
    }

    private function buildNewInstanceArgs(
        ReflectionClass $reflClass,
        array $definition
    ) {
        $instanceArgs = array();


        $reflCtor = $reflClass->getConstructor();

        // IF no constructor exists we're done and should just
        // return a new instance of $class:
        // return $this->make($reflClass->name);
        // otherwise ...

        $reflCtorParams = $reflCtor->getParameters();

        foreach ($reflCtorParams as $ctorParam) {
            if (isset($definition[$ctorParam->name])) {
                $instanceArgs[] = $this->make($definition[$ctorParam->name]);
                continue;
            }

            $typeHint = $this->getParameterTypeHint($ctorParam);

            if ($typeHint && $this->isInstantiable($typeHint)) {
                // The typehint is instantiable, go ahead and make a new
                // instance of it
                $instanceArgs[] = $this->make($typeHint);
            } elseif ($typeHint) {
                // The typehint is abstract or an interface. We can't
                // proceed because we already know we don't have a 
                // definition telling us which class to instantiate
                throw Exception;
            } elseif ($ctorParam->isDefaultValueAvailable()) {
                // No typehint, try to use the default parameter value
                $instanceArgs[] = $ctorParam->getDefaultValue();
            } else {
                // If all else fails, try passing in a NULL or something
                $instanceArgs[] = NULL;
            }
        }

        return $instanceArgs;
    }

    private function getParameterTypeHint(ReflectionParameter $param) {
        // ... see the note about retrieving parameter typehints
        // in the exposition ...
    }
    private function isInstantiable($class) {
        // determine if the class typehint is abstract/interface
        // RTM on reflection for how to do this
    }
}

关于php - 快速检查对象是否会在 PHP 中成功实例化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13517192/

有关php - 快速检查对象是否会在 PHP 中成功实例化?的更多相关文章

  1. ruby - 如何以表格格式快速打印 Ruby 哈希值? - 2

    有没有办法快速将表格格式的ruby​​哈希打印到文件中?如:keyAkeyBkeyC...1232343451253474456...其中散列的值是不同大小的数组。还是使用双循环是唯一的方法?谢谢 最佳答案 试试我写的这个gem(在表中打印散列、ruby对象、ActiveRecord对象):http://github.com/arches/table_print 关于ruby-如何以表格格式快速打印Ruby哈希值?,我们在StackOverflow上找到一个类似的问题:

  2. 电脑启动后显示器黑屏怎么办?排查下面4个问题,快速解决 - 2

    电脑启动出现显示器黑屏是一个相当常见的问题。如果您遇到了这个问题,不要惊慌,因为它有很多可能的原因,可以采取一些简单的措施来解决它。在本文中,小编将介绍下面4种常见的电脑启动后显示器黑屏的原因,排查这些原因,快速解决! 演示机型:联想Ideapad700-15ISK-ISE系统版本:Windows10一、显示器问题如果出现电脑启动后显示器黑屏的情况。那么首先您需要检查一下显示器是否正常工作。您可以通过更换另一个显示器或将当前显示器连接到另一台计算机来检查显示器是否存在问题。如果问题仍然存在,那么您可以排除显示器故障的可能性。 二、显卡问题如果您的电脑配备了独立显卡,那么显卡故障也可能是导致电脑

  3. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

  4. ruby - 脚本在命令行中成功执行但不是作为 cron 作业 - 2

    我有一个bash脚本,它运行一个ruby​​脚本来获取我的Twitter提要。##/home/username/twittercron#!/bin/bashcd/home/username/twitterrubytwitter.rbfriends命令行运行成功/home/username/twittercron但是当我尝试将它作为cronjob运行时,它运行了但无法获取提要。##crontab-e*/15*****/home/username/twittercron脚本已经chmod+x。不知道为什么会这样。有什么想法吗? 最佳答案

  5. python - 为什么某些正则表达式引擎会在单个输入字符串中匹配 .* 两次? - 2

    许多正则表达式引擎在单行字符串中匹配.*两次,例如,在执行基于正则表达式的字符串替换时:根据定义,第一个匹配项是整个(单行)字符串,正如预期的那样。在许多引擎中有第二个匹配项,即空字符串;也就是说,即使第一个匹配项消耗了整个输入字符串,.*仍会再次匹配,然后匹配输入字符串末尾的空字符串。注意:要确保只找到一个匹配项,请使用^.*我的问题是:这种行为有充分的理由吗?一旦输入字符串被完全使用,我不希望再次尝试找到匹配项。除了反复试验之外,您能否从支持的文档/正则表达式方言/标准中收集到哪些引擎表现出这种行为?更新:revo'shelpfulanswer解释当前行为的方式;至于潜在的原因,请

  6. ruby - 使单元测试快速失败以进行突变测试 - 2

    mutationtesting遇到一个问题是它很慢,因为默认情况下您会为每个生成的突变执行完整的测试运行(测试文件或一组测试文件)。加快突变测试的一种方法是,一旦遇到单一故障(但仅在突变测试期间),就停止对给定突变体的测试运行。更好的做法是让变异测试者记住杀死最后一个变异体的第一个测试是什么,并将其首先交给下一个变异体。ruby中是否有任何东西可以做这些事情,或者我最好的选择是开始猴子修补?(是的,我知道单元测试应该很快。显示所有失败的测试在突变测试之外很有用,因为它不仅可以帮助您识别出问题,还可以查明哪里出了问题)编辑:我目前正在对测试/单元使用heckle。如果测试/单元不可能记住

  7. ruby-on-rails - Rails 'service objects' 最佳实践 - 类方法或实例化 - 2

    我正在按照我一直在研究的研讨会实现“服务对象”,我正在构建一个redditAPI应用程序。我需要对象返回一些东西,所以我不能只执行初始化程序中的所有内容。我有这两个选择:选项1:类需要实例化classSubListFromUserdefuser_subscribed_subs(client)@client=client@subreddits=sort_subs_by_name(user_subs_from_reddit)endprivatedefsort_subs_by_name(subreddits)subreddits.sort_by{|sr|sr[:name].downcase}

  8. ruby-on-rails - 验证终端命令已在 Rails 中成功运行的最佳方法是什么? - 2

    我正在编写一个快速的Rails应用程序,并且想知道如何验证执行的命令是否成功。我正在运行的两个命令是SVN更新,以及从一个目录到另一个目录的cp。 最佳答案 如果您使用Kernel.system()方法,它将返回一个bool值,指示命令是否成功。result=system("cp-rdir1dir2")if(result)#dothenextthingelse#handletheerror不同的ruby系统命令有很好的比较here. 关于ruby-on-rails-验证终端命令已在Rai

  9. ruby - 为什么一个简单的瘦服务器在进行基准测试时会在 16500 个请求时停止响应? - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:'ab'programfreezesafterlotsofrequests,why?这是一个简单的测试服务器:require'rubygems'require'rack'require'thin'classHelloWorlddefcall(env)[200,{"Content-Type"=>"text/plain"},"OK"]endendRack::Handler::Thin.runHelloWorld.new,:Port=>9294#I'vetriedwiththeseaddedtoo,'rack.mu

  10. ruby - 使用和不使用 Rails 的快速 (Rspec) 测试 - 2

    我有两个类:1.Sale是ActiveRecord的子类;它的工作是将销售数据持久保存到数据库中。classSale2.SalesReport是一个标准的Ruby类;它的工作是生成和绘制有关销售的信息。classSalesReportdefinitialize(start_date,end_date)@start_date=start_date@end_date=end_dateenddefsales_in_durationSale.total_for_duration(@start_date,@end_date)end#...end因为我想使用TDD并且我希望我的测试运行得非常快,所

随机推荐