【问题标题】:Is the use of computed "include" or "required" a bad code smell?使用计算的“包含”或“必需”是不好的代码气味吗?
【发布时间】:2019-08-06 09:03:09
【问题描述】:

是否使用计算的包含/需要不良代码气味,是否对性能产生不良影响?而且我猜让包含的文件执行代码也是一件坏事,但是如果记录了这种行为可以吗?

背景信息/我提出问题的原因:

我需要调用 API 来获取有关某些服务的信息。我有大约 50 个服务,每个服务需要调用 API 0-6 次。所以我正在寻找一种配置方式

  • API 调用的参数(参数类型因调用而异,可以是字符串也可以是数组)
  • 定义要调用的 API

我想为每个包含调用的服务创建一个文件,并将信息作为单个数组返回,如下所示:

<?php

    // Params for Call 1
    $anArrayWithSomeParams = array('param1', 'param2', 'param3', 'param4');

    // Params for Call 2
    $aString = 'string1';
    $anotherString = 'string2'

    // Params for Call 3-6
    ...

    $someInformation            = $dmy->getSomeInformation($anArrayWithSomeParams);
    $notNeededHere              = NULL;
    $moreInformation            = $dmy->getMoreInformation($aString,$anotherString);
    ...

    $allData = array( '0'   => $someInformation,
                    '1'     => $notNeededHere
                    '2'     => $tablespace,
                    ....
    );
?>

然后我可以包含该文件并使用变量alldata 来访问数据并对其执行如下操作:

require_once('class.dummy.php');
$directories = array("dir1", "dir2", "dir3");
$dmy = new dummy();

foreach($directories as $path) {
    $allData = NULL;
    $executeDataCollection = $path.'myFile.php';
    require($executeDataCollection);
    print "<pre>";
    print_r($allData);
    print "</pre>";
}

虽然这可能可行,但它似乎不是一个优雅的解决方案。我想知道是否有人可以提示我以更优雅/更复杂的方式处理此问题。

提前致谢!

【问题讨论】:

  • 使用require 被认为是不好的做法。您应该使用自动装载机。但是,话虽如此,使用动态类名(这是您通过自动加载执行此操作的方式)也是不好的做法。通常在 OOP 中所做的是一个接口、多个实现它的类以及一个在需要时创建适当实例的工厂。
  • 嗨 Max,欢迎来到 StackOverflow。你刚刚问了一个很好的问题。但是,我认为这主要是基于意见的。或许你可以看看codereview.stackexchange.com

标签: php configuration


【解决方案1】:

使用 require 和任何类似的方法都是不好的做法。

您应该更多地以 OOP 方式思考如何实现这一点。为了实现这样的目标,我建议使用接口和抽象类。在您的情况下,您需要根据需要调用一些具有不同参数的 APIS,您应该使用以下模式/原则:

界面如下所示:

interface ApiGateway {

   /**
    * This will execute call with optional parameters
    *
    **/
   public function call($parameters = null);
}

抽象类

abstract class ApiGatewayAbstract implements ApiGateway
{

   /** return Adapter for handle API call **/
   abstract protected function getAdapter();
   /** return list of arguments for call */
   abstract protected function getArguments();

   public function call($parameters = null)
   {
       $adapter = $this->getAdapter();
       $arguments = $this->getArguments();

       // this will be HTTPAdapter for executing API call you need with specific params and arguments
       return $adapter->execute($arguments, $parameters);
   }
}

现在您可以开始实施特定的 ApiGateways:

class MyApiGateway extends ApiGatewayAbstract
{
    protected $arguments = [];
    protected $adapter;

    public function __construct(HttpClientInterface $httpClient, array $arguments = [])
    {
        $this->arguments = $arguments;
        $this->adapter = $httpClient;
    }

    protected function getArguments()
    {
       return $this->arguments;
    }

    protected function getAdapter()
    {
       return $this->adapter;
    }

}

最后一步是你的 ApiGateways 的工厂:

class ApiGatewayFactory
{
    // dynamic way to get Specific api gateway by name, or you can implement for each api gateway specific method
    public function getApiGateway($name, HttpClientInterface $adapter, array $arguments) 
    {
         $className = 'Namespace\\'.$name;
         if (!class_exist($className) {
            throw new \Exception('Unsuported ApiGateway');
         }

         // here you can use reflection or simply do:

         return new $className($adapter, $arguments);
    }
}

通过这种方法,您将获得您想要的干净方式,并遵循 S.O.L.I.D. 的一些原则。因此,您可以添加更多具有特定用例或不同适配器(soap、http、socket)等的 ApiGateways。

希望这会有所帮助,这也只是一个示例,看看这些模式以及如何实现它们。但是这个例子应该可以帮助你理解这种方法。

【讨论】:

  • 获取/定义参数的首选方式是什么?参数当前在包含的额外文件中定义。
  • 使用配置文件并将它们放在那里,然后像这样传递它们: $factory = new ApiGatewayFactory(); $gateway = $factory->getApiGateway('MyApiGateway', $config['arguments']); $网关->调用();不知道你的架构是如何解决的,确切的解决方案,但应该是这样的。
猜你喜欢
  • 2011-04-26
  • 2011-01-27
  • 2012-09-12
  • 2017-12-23
  • 2014-12-15
  • 2016-02-14
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多