Composer - 基于 PHP 版本在运行时修改自动加载 SRC

问题描述

我想知道是否有办法根据 PHP 版本加载不同的文件夹。我可以编写自己的自动加载器,但我想知道是否可以使用 Composer 来做到这一点?

附言。我之前在模块/插件应用程序中看到过这种情况,这些应用程序在全球重新分发以与广泛的环境一起使用。那些使用自己的自动加载类的脚本。

我很好奇有没有办法以类似的方式使用作曲家。

场景:类/文件夹结构:

class >
   PHP5.6 >
      - SomeClass.PHP
      ...
   PHP7.x >
      - SomeClass.PHP
      ...
   PHP8.x >
      - SomeClass.PHP
      ...

比较PHP版本并做一些事情:

$classpathForAutoloader = '';
if (version_compare(PHP_VERSION,'8.0.0') >= 0) {
  $classpathForAutoloader = 'PHP8.x';
  // do something to composer autoload or 
  // use declaration
}else if(version_compare(PHP_VERSION,'7.0.0') >= 0){
  $classpathForAutoloader = 'PHP7.x';
  // do something to composer autoload or 
  // use declaration
}else if(version_compare(PHP_VERSION,'5.6.0') >= 0{
  $classpathForAutoloader = 'PHP5.6';
  // do something to composer autoload or 
  // use declaration
}else{
    // throw Exception ...
}

标准作曲家设置:

{
    "name": "some/name","require": {
    },"authors": [
        {
            "name": "Some Name","email": "some@email.com"
        }
    ],"autoload": {
        "psr-4": {
            "Devwl\\": "class/","Tools\\": "tools/"           
        },"classmap": [
            "class/"
          ],"exclude-from-classmap": []
    }
}

解决方法

我认为 Composer 没有提供动态自动加载不同路径的方法。

您能否在单个 version_compare 类中仅在功能因 PHP 版本而异的情况下使用 SomeClass.php?还是将整个 SomeClass.php 写成向后兼容?

对我来说,根据 PHP 版本加载不同的类在跨环境的可重现性方面会带来麻烦。

另一种选择是使用 require_once 来加载不同的类,但为了可维护性,我真的倾向于只在绝对必要时进行版本检查的单个类。

,

所以我创建了一个类来满足我的需求。它可以与 Composer 自动加载器一起使用。

<?php

class PhpVersionAutoloader{
  private $baseClassesDirPath = null;
  private $phpVersionArr = [];
  private $phpDir = null;
  private $classes = []; /** Keep a record of all loaded classes */

  /**
   * Allows to change base dir path.
   * If not set the path will be set to file _DIR_
   * 
   * @see $this->baseClassesDirPath
   *
   * @param string $path
   * @return void
   */
  public function setBaseClassesDirPath($path)
  {
    $this->baseClassesDirPath = $path;
  }

  /**
   * Map available dir name and php version
   * 
   * @see $this->phpVersionArr
   *
   * @param string $directory name 
   * @param string $phpVersion
   * @return void
   */
  public function registerPhpDir($dir,$phpVersion){
    $this->phpVersionArr[] = [$dir => $phpVersion];
  }

  /**
   * Compare curent php version with  $this->phpVersionArr to determin the right path for class load
   */
  public function selectPhpDir(){

    foreach ($this->phpVersionArr as $key => $phpVDir) {
      $this->position = $key;
      foreach($phpVDir as $key => $value){
        if (version_compare(PHP_VERSION,$value) >= 0){
          $this->phpDir = $key;
          break 2;
        }
      }
    }
  }

  /**
   * Register autloader
   *
   * @return void
   */
  public function register(){
    spl_autoload_register(function($className)
    {
        $namespace = str_replace("\\","/",__NAMESPACE__);
        $className = str_replace("\\",$className);

        $this->baseClassesDirPath = ($this->baseClassesDirPath === null) ? str_replace("\\",__DIR__) : $this->baseClassesDirPath;

        $class = $this->baseClassesDirPath."/classes/".$this->phpDir.'/'. (empty($namespace)?"":$namespace."/")."{$className}.php";
        $this->classes[] = $class;
        
        if (file_exists($class)){
          include_once($class);
        }else{
          // ... if not exsist try to load lower php version file?
          // ... or throw new Error("Error Processing Request",1);
          
        }
    });
  }

}

像这样使用 PhpVersionAutoloader 对象:

/**
 * Use example
 */
$loader = new PhpVersionAutoloader(); // init PhpVersionAutoloader object
$loader->setBaseClassesDirPath('C:/xampp/htdocs/blog/blog autoloading'); // if not used will use _DIR_ to create path

$loader->registerPhpDir('php8.x','8.0.0'); // as "folder name" => "php version" 
$loader->registerPhpDir('php7.x','7.0.0'); // ...
$loader->registerPhpDir('php5.6','5.6.0'); // ...

$loader->selectPhpDir(); // compare system php version and selects the correct phpX.X subfolder
$loader->register(); // register autoloader

我还创建了这个加载器的更多功能类,它允许强制从特定目录加载,甚至允许从旧版本的 PHP 加载类(如果在所选版本中找不到)。

见github [here]

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...