Skip to content

Latest commit

 

History

History
270 lines (218 loc) · 10.5 KB

README_ZH.md

File metadata and controls

270 lines (218 loc) · 10.5 KB

PHP Migration

Build Status Total Downloads Latest Stable Version License

这是一个用于PHP版本迁移和兼容性检查的代码静态分析器。

主要功能是检查当前代码在新版本PHP下的兼容性并提供相关的建议及处理方法。

它能够简化升级PHP版本时的步骤,做到精确检查避免遗漏,最终的目标是代替人工检查代 码。

有以下特性:

  • 检查全面,覆盖PHP 5.3至7.0中绝大部分改动
  • 严谨不遗漏,并做到尽可能精准
  • 零配置,下载即用
  • 可以快速开发适用于个人项目的检查

相比于类似项目PHP Compatibility 因为PHP Compatibility是作为代码规范,并基于PHP_CodeSniff开发的 导致缺乏一定的灵活度,致使无法覆盖到某些检查 此处无意贬低,只是客观对比

注意:本项目依然处在早期开发阶段,请谨慎用于生产环境

安装及使用

  1. 你可以通过下面命令下载一个封装好的可执行的Phar文件

    wget https://github.com/monque/PHP-Migration/releases/download/v0.2.2/phpmig.phar
    
  2. 执行下面命令,将会对该文件进行检查,并输出报告

    php phpmig.phar sample.php
    

    假设下面代码保存在sample.php文件中,

    <?php
    // Fatal error: Only variables can be passed by reference
    array_shift(array(1, 2));
    sort(array(1, 2, 3));
    
    // __DIR__ is pre-defined
    define('__DIR__', dirname(__FILE__));
    
    // Fatal error: Cannot redeclare class_alias()
    function class_alias() {}
    
    // This is fine
    if (!function_exists('class_alias')) {
        function class_alias() {}
    }
    
    // Fatal error: Call-time pass-by-reference has been removed
    array_map('trim', &$_SERVER);
    
    // Fatal error: 'break' operator with non-constant operand is no longer supported
    while (true) {
        break $a;
    }
    
    // Fatal error: Cannot re-assign auto-global variable _GET
    function ohno($_GET) {}
    
    // Array keys won't be overwritten when defining an array as a property of a class via an array literal
    class C {
        const ONE = 1;
        public $array = [
            self::ONE => 'foo',
            'bar',
            'quux',
        ];
    }
    
    // set_exception_handler() is no longer guaranteed to receive Exception objects
    set_exception_handler(function (Exception $e) { });
    
    // Changes to the handling of indirect variables, properties, and methods
    echo $$foo['bar']['baz'];
    
    // foreach no longer changes the internal array pointer
    foreach ($list as &$row) {
        current($list);
    }
  3. 报告输出内容如下 表中各列含义如下:行号,问题级别,是否确认,起始版本,详细信息

    File: sample.php
    --------------------------------------------------------------------------------
    Found 11 spot(s), 10 identified
    --------------------------------------------------------------------------------
        3 | FATAL      | * | 5.3.0 | Only variables can be passed by reference
        4 | FATAL      | * | 5.3.0 | Only variables can be passed by reference
        7 | WARNING    | * | 5.3.0 | Constant "__DIR__" already defined
       10 | FATAL      | * | 5.3.0 | Cannot redeclare class_alias()
       18 | FATAL      | * | 5.4.0 | Call-time pass-by-reference has been removed
       22 | FATAL      | * | 5.4.0 | break operator with non-constant operand is no longer supported
       26 | FATAL      | * | 5.4.0 | Cannot re-assign auto-global variable
       31 | WARNING    |   | 5.6.0 | Array key may be overwritten when defining as a property and using constants
       39 | WARNING    | * | 7.0.0 | set_exception_handler() is no longer guaranteed to receive Exception objects
       42 | WARNING    | * | 7.0.0 | Different behavior between PHP 5/7
       46 | NOTICE     | * | 7.0.0 | foreach no longer changes the internal array pointer
    --------------------------------------------------------------------------------
    

    关于第三列是否确认的含义,在下面会有详细的解释。

选择检查组

一个检查组由多个检查点组成,并且检查组可以指定对其他检查组的依赖。

通过php phpmig.phar -l列出全部检查组。

classtree  => List contents of classes in a tree-like format
to53       => Migrating from ANY version to PHP 5.3.x
to54       => Migrating from ANY version to PHP 5.4.x
to55       => Migrating from ANY version to PHP 5.5.x
to56       => Migrating from ANY version to PHP 5.6.x
to70       => Migrating from ANY version to PHP 7.0.x
v53        => Migrating from PHP 5.2.x to PHP 5.3.x
v54        => Migrating from PHP 5.3.x to PHP 5.4.x
v55        => Migrating from PHP 5.4.x to PHP 5.5.x
v56        => Migrating from PHP 5.5.x to PHP 5.6.x
v70        => Migrating from PHP 5.6.x to PHP 7.0.x

并通过php phpmig.phar -s <setname>选择要使用的检查组。

关于检查组设置的说明

举例说明,to56是指从任意版本升级至5.6时所用的检查。 它依赖v56to55,其中v56仅包含了PHP 5.6引入的改动的检查点,to55则依赖v55to54,以此类推。 通过这种递归依赖的机制,即可实现任意版本到某固定版本的检查。

其他用法:输出类的继承关系树

类似于常见的tree命令,通过php phpmig.phar -s classtree .会扫描项目中的类继 承关系,并输出一个树状的图

|-- PhpMigration\App
|-- PhpMigration\Changes\AbstractChange
|   |-- PhpMigration\Changes\AbstractIntroduced
|   |   |-- PhpMigration\Changes\v5dot3\Introduced
|   |   |-- PhpMigration\Changes\v5dot4\Introduced
|   |   |-- PhpMigration\Changes\v5dot5\Introduced
|   |   |-- PhpMigration\Changes\v5dot6\Introduced
|   |   `-- PhpMigration\Changes\v7dot0\Introduced
|   |-- PhpMigration\Changes\AbstractKeywordReserved
|   |   |-- PhpMigration\Changes\v5dot3\IncompReserved
|   |   `-- PhpMigration\Changes\v5dot4\IncompReserved
|   |-- PhpMigration\Changes\AbstractRemoved
|   |   |-- PhpMigration\Changes\v5dot3\Removed
|   |   |-- PhpMigration\Changes\v5dot4\Removed
|   |   |-- PhpMigration\Changes\v5dot5\Removed
|   |   |-- PhpMigration\Changes\v5dot6\Removed
|   |   `-- PhpMigration\Changes\v7dot0\Removed
|   |-- PhpMigration\Changes\ClassTree
|   |-- PhpMigration\Changes\Dev
|   |-- PhpMigration\Changes\v5dot3\Deprecated
|   |-- PhpMigration\Changes\v5dot3\IncompByReference
|   |-- PhpMigration\Changes\v5dot3\IncompCallFromGlobal
|   |-- PhpMigration\Changes\v5dot3\IncompMagic
|   |-- PhpMigration\Changes\v5dot3\IncompMagicInvoked
|   |-- PhpMigration\Changes\v5dot3\IncompMisc
|   |-- PhpMigration\Changes\v5dot4\Deprecated
|   |-- PhpMigration\Changes\v5dot4\IncompBreakContinue
|   |-- PhpMigration\Changes\v5dot4\IncompByReference
|   |-- PhpMigration\Changes\v5dot4\IncompHashAlgo
|   |-- PhpMigration\Changes\v5dot4\IncompMisc
|   |-- PhpMigration\Changes\v5dot4\IncompParamName
|   |-- PhpMigration\Changes\v5dot4\IncompRegister
|   |-- PhpMigration\Changes\v5dot5\Deprecated
|   |-- PhpMigration\Changes\v5dot5\IncompCaseInsensitive
|   |-- PhpMigration\Changes\v5dot5\IncompPack
|   |-- PhpMigration\Changes\v5dot6\Deprecated
|   |-- PhpMigration\Changes\v5dot6\IncompMisc
|   |-- PhpMigration\Changes\v5dot6\IncompPropertyArray
|   |-- PhpMigration\Changes\v7dot0\Deprecated
|   |-- PhpMigration\Changes\v7dot0\ExceptionHandle
|   |-- PhpMigration\Changes\v7dot0\ForeachLoop
|   |-- PhpMigration\Changes\v7dot0\FuncList
|   |-- PhpMigration\Changes\v7dot0\FuncParameters
|   |-- PhpMigration\Changes\v7dot0\IntegerOperation
|   |-- PhpMigration\Changes\v7dot0\KeywordReserved
|   |-- PhpMigration\Changes\v7dot0\ParseDifference
|   |-- PhpMigration\Changes\v7dot0\StringOperation
|   `-- PhpMigration\Changes\v7dot0\SwitchMultipleDefaults
|-- PhpMigration\CheckVisitor
|-- PhpMigration\Logger
|-- PhpMigration\ReduceVisitor
|-- PhpMigration\SymbolTable
|-- PhpMigration\Utils\FunctionListExporter
|-- PhpMigration\Utils\Logging
|-- PhpMigration\Utils\Packager
`-- PhpMigration\Utils\ParserHelper

通过源代码安装

  1. 将本项目clone到本地,并进入项目目录

    git clone https://github.com/monque/PHP-Migration.git php-migration
    cd php-migration
    
  2. 执行下面命令来安装 Composer,并通过Composer安装项目所需的依赖

    curl -sS https://getcomposer.org/installer | php
    php composer.phar install
    
  3. 可以通过执行下面命令来运行本程序

    php bin/phpmig
    

原理、处理流程

处理流程

flow

输出中第三列是否确认的含义说明

坦诚的讲,有些存在隐患的改动是永远无法精确检查的。 比如PHP 5.5中unpack的'a'表示的格式发生变化(官方描述),并产生了不向下兼容的影响。

以下面代码为例:

<?php
unpack($obj->getFormat(), $data); // OMG, What is $obj? How getFormat() works?
unpack('b3', $data); // Works in new version
unpack('a3', $data); // Affected

通过对参数值的猜测,能够区分出三种不同级别,并进行不同处理

级别 确定 报错
确定产生影响
确定不会影响
可能产生影响

最终输出如下:

--------------------------------------------------------------------------------
Found 2 spot(s), 1 identified
--------------------------------------------------------------------------------
   2 | WARNING    |   | 5.5.0 | Behavior of pack() with "a", "A" in format is changed
   4 | WARNING    | * | 5.5.0 | Behavior of pack() with "a", "A" in format is changed
--------------------------------------------------------------------------------

这样做即保证了不遗漏,也大幅减少了人工干预。

许可

本项目遵循MIT许可进行发布