Phan is a static analyzer for PHP. Phan prefers to avoid false-positives and attempts to prove incorrectness rather than correctness.

Overview

Phan is a static analyzer for PHP that prefers to minimize false-positives. Phan attempts to prove incorrectness rather than correctness.

Phan looks for common issues and will verify type compatibility on various operations when type information is available or can be deduced. Phan has a good (but not comprehensive) understanding of flow control and can track values in a few use cases (e.g. arrays, integers, and strings).

Build Status Build Status (Windows) Gitter Latest Stable Version License

This is the branch for Phan 4. The branch for the older Phan 3 release line is here.

Getting Started

The easiest way to use Phan is via Composer.

composer require phan/phan

With Phan installed, you'll want to create a .phan/config.php file in your project to tell Phan how to analyze your source code. Once configured, you can run it via ./vendor/bin/phan.

Phan depends on PHP 7.2+ with the php-ast extension (1.0.10+ is preferred) and supports analyzing PHP version 7.0-8.0 syntax. Installation instructions for php-ast can be found here. (Phan can be used without php-ast by using the CLI option --allow-polyfill-parser, but there are slight differences in the parsing of doc comments)

  • Alternative Installation Methods
    See Getting Started for alternative methods of using Phan and details on how to configure Phan for your project.
  • Incrementally Strengthening Analysis
    Take a look at Incrementally Strengthening Analysis for some tips on how to slowly ramp up the strictness of the analysis as your code becomes better equipped to be analyzed.
  • Installing Dependencies
    Take a look at Installing Phan Dependencies for help getting Phan's dependencies installed on your system.

The Wiki has more information about using Phan.

Features

Phan is able to perform the following kinds of analysis:

  • Check that all methods, functions, classes, traits, interfaces, constants, properties and variables are defined and accessible.
  • Check for type safety and arity issues on method/function/closure calls.
  • Check for PHP7/PHP5 backward compatibility.
  • Check for features that weren't supported in older PHP 7.x minor releases (E.g. object, void, iterable, ?T, [$x] = ...;, negative string offsets, multiple exception catches, etc.)
  • Check for sanity with array accesses.
  • Check for type safety on binary operations.
  • Check for valid and type safe return values on methods, functions, and closures.
  • Check for No-Ops on arrays, closures, constants, properties, variables, unary operators, and binary operators.
  • Check for unused/dead/unreachable code. (Pass in --dead-code-detection)
  • Check for unused variables and parameters. (Pass in --unused-variable-detection)
  • Check for redundant or impossible conditions and pointless casts. (Pass in --redundant-condition-detection)
  • Check for unused use statements. These and a few other issue types can be automatically fixed with --automatic-fix.
  • Check for classes, functions and methods being redefined.
  • Check for sanity with class inheritance (e.g. checks method signature compatibility). Phan also checks for final classes/methods being overridden, that abstract methods are implemented, and that the implemented interface is really an interface (and so on).
  • Supports namespaces, traits and variadics.
  • Supports Union Types.
  • Supports Generic Types (i.e. @template).
  • Supports generic arrays such as int[], UserObject[], array<int,UserObject>, etc..
  • Supports array shapes such as array{key:string,otherKey:?stdClass}, etc. (internally and in PHPDoc tags) This also supports indicating that fields of an array shape are optional via array{requiredKey:string,optionalKey?:string} (useful for @param)
  • Supports phpdoc type annotations.
  • Supports inheriting phpdoc type annotations.
  • Supports checking that phpdoc type annotations are a narrowed form (E.g. subclasses/subtypes) of the real type signatures
  • Supports inferring types from assert() statements and conditionals in if elements/loops.
  • Supports @deprecated annotation for deprecating classes, methods and functions
  • Supports @internal annotation for elements (such as a constant, function, class, class constant, property or method) as internal to the package in which it's defined.
  • Supports @suppress <ISSUE_TYPE> annotations for suppressing issues.
  • Supports magic @property annotations (@property <union_type> <variable_name>)
  • Supports magic @method annotations (@method <union_type> <method_name>(<union_type> <param1_name>))
  • Supports class_alias annotations (experimental, off by default)
  • Supports indicating the class to which a closure will be bound, via @phan-closure-scope (example)
  • Supports analysis of closures and return types passed to array_map, array_filter, and other internal array functions.
  • Offers extensive configuration for weakening the analysis to make it useful on large sloppy code bases
  • Can be run on many cores. (requires pcntl)
  • Output is emitted in text, checkstyle, json, pylint, csv, or codeclimate formats.
  • Can run user plugins on source for checks specific to your code. Phan includes various plugins you may wish to enable for your project.

See Phan Issue Types for descriptions and examples of all issues that can be detected by Phan. Take a look at the \Phan\Issue to see the definition of each error type.

Take a look at the Tutorial for Analyzing a Large Sloppy Code Base to get a sense of what the process of doing ongoing analysis might look like for you.

Phan can be used from various editors and IDEs for its error checking, "go to definition" support, etc. via the Language Server Protocol. Editors and tools can also request analysis of individual files in a project using the simpler Daemon Mode.

See the tests directory for some examples of the various checks.

Phan is imperfect and shouldn't be used to prove that your PHP-based rocket guidance system is free of defects.

Features provided by plugins

Additional analysis features have been provided by plugins.

Example: Phan's plugins for self-analysis.

Usage

After installing Phan, Phan needs to be configured with details on where to find code to analyze and how to analyze it. The easiest way to tell Phan where to find source code is to create a .phan/config.php file. A simple .phan/config.php file might look something like the following.

<?php

/**
 * This configuration will be read and overlaid on top of the
 * default configuration. Command line arguments will be applied
 * after this file is read.
 */
return [

    // Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`, `'7.4'`,
    // `'8.0'`, `null`.
    // If this is set to `null`,
    // then Phan assumes the PHP version which is closest to the minor version
    // of the php executable used to execute Phan.
    "target_php_version" => null,

    // A list of directories that should be parsed for class and
    // method information. After excluding the directories
    // defined in exclude_analysis_directory_list, the remaining
    // files will be statically analyzed for errors.
    //
    // Thus, both first-party and third-party code being used by
    // your application should be included in this list.
    'directory_list' => [
        'src',
        'vendor/symfony/console',
    ],

    // A directory list that defines files that will be excluded
    // from static analysis, but whose class and method
    // information should be included.
    //
    // Generally, you'll want to include the directories for
    // third-party code (such as "vendor/") in this list.
    //
    // n.b.: If you'd like to parse but not analyze 3rd
    //       party code, directories containing that code
    //       should be added to the `directory_list` as
    //       to `exclude_analysis_directory_list`.
    "exclude_analysis_directory_list" => [
        'vendor/'
    ],

    // A list of plugin files to execute.
    // Plugins which are bundled with Phan can be added here by providing their name
    // (e.g. 'AlwaysReturnPlugin')
    //
    // Documentation about available bundled plugins can be found
    // at https://github.com/phan/phan/tree/v4/.phan/plugins
    //
    // Alternately, you can pass in the full path to a PHP file
    // with the plugin's implementation.
    // (e.g. 'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php')
    'plugins' => [
        // checks if a function, closure or method unconditionally returns.
        // can also be written as 'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'
        'AlwaysReturnPlugin',
        'DollarDollarPlugin',
        'DuplicateArrayKeyPlugin',
        'DuplicateExpressionPlugin',
        'PregRegexCheckerPlugin',
        'PrintfCheckerPlugin',
        'SleepCheckerPlugin',
        // Checks for syntactically unreachable statements in
        // the global scope or function bodies.
        'UnreachableCodePlugin',
        'UseReturnValuePlugin',
        'EmptyStatementListPlugin',
        'LoopVariableReusePlugin',
    ],
];

Take a look at Creating a Config File and Incrementally Strengthening Analysis for more details.

Running phan --help will show usage information and command-line options.

Annotating Your Source Code

Phan reads and understands most PHPDoc type annotations including Union Types (like int|MyClass|string|null) and generic array types (like int[] or string[]|MyClass[] or array<int,MyClass>).

Take a look at Annotating Your Source Code and About Union Types for some help getting started with defining types in your code.

Phan supports (int|string)[] style annotations, and represents them internally as int[]|string[] (Both annotations are treated like array which may have integers and/or strings). When you have arrays of mixed types, just use array.

The following code shows off the various annotations that are supported.

/**
 * @return void
 */
function f() {}

/** @deprecated */
class C {
    /** @var int */
    const C = 42;

    /** @var string[]|null */
    public $p = null;

    /**
     * @param int|null $p
     * @return string[]|null
     */
    public static function f($p) {
        if (is_null($p)) {
            return null;
        }

        return array_map(
            /** @param int $i */
            function($i) {
                return "thing $i";
            },
            range(0, $p)
        );
    }
}

Just like in PHP, any type can be nulled in the function declaration which also means a null is allowed to be passed in for that parameter.

Phan checks the type of every single element of arrays (Including keys and values). In practical terms, this means that [$int1=>$int2,$int3=>$int4,$int5=>$str6] is seen as array<int,int|string>, which Phan represents as array<int,int>|array<int,string>. [$strKey => new MyClass(), $strKey2 => $unknown] will be represented as array<string,MyClass>|array<string,mixed>.

  • Literals such as [12,'myString'] will be represented internally as array shapes such as array{0:12,1:'myString'}

Generating a file list

This static analyzer does not track includes or try to figure out autoloader magic. It treats all the files you throw at it as one big application. For code encapsulated in classes this works well. For code running in the global scope it gets a bit tricky because order matters. If you have an index.php including a file that sets a bunch of global variables and you then try to access those after the include(...) in index.php the static analyzer won't know anything about these.

In practical terms this simply means that you should put your entry points and any files setting things in the global scope at the top of your file list. If you have a config.php that sets global variables that everything else needs, then you should put that first in the list followed by your various entry points, then all your library files containing your classes.

Development

Take a look at Developer's Guide to Phan for help getting started hacking on Phan.

When you find an issue, please take the time to create a tiny reproducing code snippet that illustrates the bug. And once you have done that, fix it. Then turn your code snippet into a test and add it to tests then ./test and send a PR with your fix and test. Alternatively, you can open an Issue with details.

To run Phan's unit tests, just run ./test.

To run all of Phan's unit tests and integration tests, run ./tests/run_all_tests.sh

Code of Conduct

We are committed to fostering a welcoming community. Any participant and contributor is required to adhere to our Code of Conduct.

Online Demo

This requires an up to date version of Firefox/Chrome and at least 4 GB of free RAM. (this is a 15 MB download)

Run Phan entirely in your browser.

Preview of analyzing PHP

Comments
  • Language analyzer as a service

    Language analyzer as a service

    Have you thought ahead as far as allowing for the static code analysis engine to run as (part of) a service?

    That is, I'd like to eventually run the language analyzer in the background, continuously integrating changed files into the working model and providing updated analysis - e.g. allowing it to run as a service with (say) a REST API to which any modern IDE or text-editor could connect and continuously obtain information about the source-code.

    Typescript has the right approach to this, with it's incremental compiler/analyzer which runs as a service, and has enabled quick, accurate integration with a range of IDEs and editors.

    It would be really awesome if we could have consistent static analysis at design-time on our local systems, as on our continuous integration server, so I think it's worth thinking ahead to this?

    enhancement 
    opened by mindplay-dk 23
  • Phan exiting without any sign

    Phan exiting without any sign

    I do not have anything to start with. Could you start me up?

    viktor@mail:~/tmp/woocommerce-custom-orders-table$ php -c ./php.ini ./phan.phar --progress-bar; echo
    A future major version of Phan will require php-ast 1.0.1+ for AST version 70. php-ast 0.1.6 is installed.
    (Set PHAN_SUPPRESS_AST_UPGRADE_NOTICE=1 to suppress this message)
       analyze ██████████████████████████████████████████████████████░░░░░░  90% 1306MB/1306MB
    viktor@mail:~/tmp/woocommerce-custom-orders-table$ echo $?
    0
    

    at minimum_severity 6 and 7 but not at 5

    v1.3.1 on PHP 7.2

    RAM size is 12 GB

    enhancement 
    opened by szepeviktor 17
  • PHP Fatal error: Out of memory (allocated 476053504) on Windows running php through cygwin

    PHP Fatal error: Out of memory (allocated 476053504) on Windows running php through cygwin

    I use phan from within cygwin and it was working fine in my setup, but apparently the 'intl' plugin was missing to enable correct verification of its usage.

    After updating cygwin and installing "intl" I now get the following error: PHP Fatal error: Out of memory (allocated 476053504) (tried to allocate 20480 bytes) in .../phan/vendor/phan/phan/src/Phan/AST/Parser.php on line 156

    "memory_limit" is set to 4096M .

    Whatever I try, the program always fails at about 454MB. I did the following:

    • Checked with "phpinfo();" inserted in the phan startup script that it was set correctly. It is in line with my php.ini setting or with a 'php.d/memory.ini' setting that I added.;
    • Limiting memory to 24MB, still allows the program to fail at the higher limit of 454MB;
    • Passing '--memory-limit 4096M' as an option to phan still has the program failing at 454MB.

    Line 156 corresponds to the following piece of code:

                $root_node = \ast\parse_code(
                    $file_contents,
                    Config::AST_VERSION,
                    $file_path
                );
    

    which is an ast operation.

    Apparently there is a different memory limit for ast than there is for php because changing the memory limit has no effect even when setting a lower value.

    I tried to find a memory option for AST to no avail.

    Any suggestion?

    question 
    opened by mdeweerd 15
  • Proposal: Split up plugins into Parse, BeforeAnalysis, and Analysis plugin interfaces

    Proposal: Split up plugins into Parse, BeforeAnalysis, and Analysis plugin interfaces

    Parse may be unnecessary, looking at the code.

    Motivations

    1. This makes it clearer when a given plugin step would be run, and whether or not authors should expect a function to be run in parallel
    2. This makes it faster to run a large number of plugins - If they're only for BeforeAnalysis (e.g. checking if a function declaration follows naming conventions, checking that __sleep is implemented, etc.), then you can skip those Plugin instances in the Analysis phase (visit() isn't called)
    3. Easier to add new abstract methods in the future. E.g. finalize()

    Proposed implementation:

    1. Add 2/3 new interfaces for ParsePlugin, BeforeAnalysisPlugin (e.g. to analyze classes and methods once all code is parsed), and AnalysisPlugin (names to be determined)
    2. The old plugin class would implement all 3 of these interfaces, for backwards compatibility
    3. All plugins checked into phan would be migrated to implement only the interfaces they use
    4. ConfigPluginSet::instance()->preAnalyzeNode would loop over classes implementing AnalysisPlugin only, etc.

    EDIT: similarly, AnalysisPlugin could be moved into AnalysisPluginVisitor (trait/interface)

    • Declare which visit methods are callable (either explicitly, or by using ReflectionClass and ReflectionMethod to determine if the no-op base class implementation is used
    • If 3 or more AnalysisPluginVisitors are added, this may be faster (E.g. visitVar would be called twice instead of three times, only on the DollarDollarPlugin. visitDim may be called once instead of three times.)
    • This cuts down on the boilerplate in plugins, if the only thing the plugin does is declare a visit method which returns an AnalysisVisitor
    question 
    opened by TysonAndre 14
  • segfault in php on current master:  49d1bd5

    segfault in php on current master: 49d1bd5

    I am getting a reproducable segfault running the latest master:

    THis is the final output: ../../phan/phan -f phan_files.txt -i -p analyze ▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰ 60% 181MB/182MB Segmentation fault

    It progresses rather quickly up to this point and then hangs for more than 5 minutes before segfaulting.

    I am happy to investigate further if someone is kind enough to tell me what to do :)

    bug 
    opened by DerManoMann 14
  • Restore passing full Context to UnaddressableTypedElements

    Restore passing full Context to UnaddressableTypedElements

    This patch makes UnaddressableTypedElements take a Context instead of a FileRef in the constructor. It is a partial revert of ea82b9948aa1263c5858ffbe780034bcd842e811 and d784029fc2d610fb56188422c5866a68da51c47d (this one for what concerns moving getContext).

    The original rationale was that avoiding the full Context brought a 5% memory saving. I did some tests with this patch in place with--print-memory-usage-summary; results are:

    • MediaWiki core (wikimedia/mediawiki): 2474MB/2474 -> 2490MB/2490
    • A MediaWiki extension (wikimedia/mediawiki-extensions-AbuseFilter): 2310MB/2312 -> 2318MB/2321
    • Phan itself: 364MB/487 -> 368MB/490

    So apparently the saved memory is 0.62% on average. IMHO, this is not enough to reduce the amount of information around, because I think the actual gain is not noticeable by people. Instead, there might be situations where the context of a variable may come up handy. More specifically I'm talking about plugins: I already have a use case for it, but I guess other people may do as well.

    Before sending this patch, I also wondered whether a config setting could be introduced to decide whether UnaddressableTypedElements should use FileRef or Context. However, given that nothing would change for the end user, and that as I said the memory gain is low, I decided not to do that. At any rate, I'm definitely open to suggestions.

    opened by Daimona 13
  • Advice: best way to restructure this code so Phan is happy

    Advice: best way to restructure this code so Phan is happy

    I have a function I simply can't get Phan to accept without a warning and I wondered if anyone has suggestions on what might work:

    class Foo
    {
    	/**
    	 * An array of static hostnames.
    	 *
    	 * @var ?array
    	 */
    	protected $_staticHostnames = null;
    
    	public function staticHostname()
    	{
    		if ($this->_staticHostnames !== null) {
    			return $this->_staticHostnames[0];
    		}
    		return '';
    	}
    }
    

    This is a trimmed example to show the problem.

    The error from Phan I get is for the return $this->_staticHostnames[0]; line: PhanTypeArraySuspiciousNullable Suspicious array access to nullable ?array

    Any thoughts?

    question 
    opened by far-blue 13
  • The

    The "@var" type comments on variables are ignored

    I have code like this:

    class kApplication
    {
    
        /**
         * Get's real class name for pseudo class
         *
         * @param string $pseudo_class
         *
         * @return kBase
         */
        public function makeClass($pseudo_class, $arguments = Array ())
        {
            return $this->Factory->makeClass($pseudo_class, $arguments);
        }
    
        public function testMethod()
        {
            /** @var kEmail $email */
            $email = $this->makeClass('....');
            $email->sendEmail();
        }
    
    }
    

    During analysis process only @return annotation of \kApplication::makeClass method is inspected and @var type override annotation in the \kApplication::testMethod method isn't taken into account.

    This results in $email variable in \kApplication::testMethod method considered of kBase type instead of kEmail type.

    Error message I'm getting is:

    core/kernel/application.php:2542 PhanUndeclaredMethod Call to undeclared method \kBase::sendEmail
    

    The Comment::fromStringInContext call in Phan is dealing with such things, but it only is used to parse DocBlock of function/method/class/class property, but not variables inside methods/functions.

    I have should_visit_all_nodes config setting enabled.

    duplicate question 
    opened by aik099 13
  • Demo of generic classes that are parameterized by template types

    Demo of generic classes that are parameterized by template types

    This patch adds (incomplete) support for generic classes. I'd be very happy to get comments on if this makes sense.

    Some Rules

    • All template types must be declared on the class via doc block comments via the @template annotation.
    • All template types must be filled in with concrete types in the constructor.
    • Classes extending generic classes need to fill in the types of the generic parent class via the @extends annotation.
    • Constants and static methods on a generic class cannot reference template types.

    How It Works

    When a class is made generic by declaring template types, the Class's scope will be made aware of the template types so that properties and methods can refer to them via @var, @param and @return. When the class is analyzed, checks will be done by assuming that the template types are some undefined class.

    Given the rule that a generic class needs to have all templates mapped to concrete types in the constructor, Phan will express the type of new C(...) not as Type('C'), but as Type('C<T>') for parameter type T. This way, whenever a property is referenced or a method is called on the instance, the declared type of the property or return type of the method will be mapped from template types to concrete types using the map on the Type associated with the instance.

    Example Generic Classes

    The following implementation of Tuple2 shows off how generics work.

    <?php declare(strict_types=1);
    
    /**
     * A tuple of 1 element.
     *
     * @template T0
     * The type of element zero
     */
    class Tuple1 extends Tuple
    {
        /** @var int */
        const ARITY = 1;
    
        /** @var T0 */
        public $_0;
    
        /**
         * @param T0 $_0
         * The 0th element
         */
        public function __construct($_0) {
            $this->_0 = $_0;
        }
    
        /**
         * @return int
         * The arity of this tuple
         */
        public function arity() : int
        {
            return static::ARITY;
        }
    
        /**
         * @return array
         * An array of all elements in this tuple.
         */
        public function toArray() : array
        {
            return [
                $this->_0,
            ];
        }
    }
    
    /**
     * A tuple of 2 elements.
     *
     * @template T0
     * The type of element zero
     *
     * @template T1
     * The type of element one
     *
     * @extends Tuple1<T0>
     */
    class Tuple2 extends Tuple1
    {
        /** @var int */
        const ARITY = 2;
    
        /** @var T1 */
        public $_1;
    
        /**
         * @param T0 $_0
         * The 0th element
         *
         * @param T1 $_1
         * The 1st element
         */
        public function __construct($_0, $_1) {
            parent::__construct($_0);
            $this->_1 = $_1;
        }
    
        /**
         * @return array
         * An array of all elements in this tuple.
         */
        public function toArray() : array
        {
            return [
                $this->_0,
                $this->_1,
            ];
        }
    }
    

    As a further example, here's what an implementation of Option, Some and None might look like.

    <?php declare(strict_types=1);
    
    /**
     * @template T
     * The type of the element
     */
    abstract class Option
    {
        /**
         * @param T $else
         * @return T
         */
        abstract public function getOrElse($else);
    
        /**
         * @return bool
         */
        abstract public function isDefined() : bool;
    
        /**
         * @return T
         */
        abstract public function get();
    }
    
    /**
     * @template T
     * The type of the element
     *
     * @extends Option<T>
     */
    class Some extends Option
    {
        /** @var T */
        private $_;
    
        /**
         * @param T $_
         */
        public function __construct($_)
        {
            $this->_ = $_;
        }
    
        /**
         * @return bool
         */
        public function isDefined() : bool
        {
            return true;
        }
    
        /**
         * @return T
         */
        public function get()
        {
            return $this->_;
        }
    
        /**
         * @param T $else
         * @return T
         */
        public function getOrElse($else)
        {
            return $this->get();
        }
    
        /**
         * @return string
         * A string representation of this object
         */
        public function __tostring() : string
        {
            return 'Some(' . $this->_ . ')';
        }
    }
    
    /**
     * @extends Option<null>
     */
    class None extends Option
    {
        /**
         * Get a new instance of nothing
         */
        public function __construct()
        {
        }
    
        /**
         * @return bool
         */
        public function isDefined() : bool
        {
            return false;
        }
    
        /**
         * @param mixed $else
         * @return mixed
         */
        public function getOrElse($else)
        {
            return $else;
        }
    
        /**
         * @return null
         */
        public function get()
        {
            throw new \Exception("Cannot call get on None");
            return null;
        }
    
        /**
         * @return string
         * A string representation of this object
         */
        public function __tostring() : string
        {
            return 'None()';
        }
    }
    
    enhancement 
    opened by morria 13
  • TypeError: Return value of Phan\Language\Scope::getParentScope() must be an instance of Phan\Language\Scope, null returned

    TypeError: Return value of Phan\Language\Scope::getParentScope() must be an instance of Phan\Language\Scope, null returned

    Hi

    I just updated phan to the latest version, and I'm now getting the following error when running:

    ~/.composer/vendor/etsy/phan/phan -i
    
    TypeError: Return value of Phan\Language\Scope::getParentScope() must be an instance of Phan\Language\Scope, null returned in /home/oli/.composer/vendor/etsy/phan/src/Phan/Language/Scope.php:54
    Stack trace:
    #0 /home/oli/.composer/vendor/etsy/phan/src/Phan/Language/Scope.php(93): Phan\Language\Scope->getParentScope()
    #1 /home/oli/.composer/vendor/etsy/phan/src/Phan/Language/Context.php(277): Phan\Language\Scope->getClassFQSEN()
    #2 /home/oli/.composer/vendor/etsy/phan/src/Phan/Language/Context.php(296): Phan\Language\Context->getClassFQSEN()
    #3 /home/oli/.composer/vendor/etsy/phan/src/Phan/Language/UnionType.php(535): Phan\Language\Context->getClassInScope(Object(Phan\CodeBase))
    #4 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/ContextNode.php(167): Phan\Language\UnionType->asClassList(Object(Phan\CodeBase), Object(Phan\Language\Context))
    #5 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/ContextNode.php(730): Phan\AST\ContextNode->getClassList()
    #6 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/UnionTypeVisitor.php(934): Phan\AST\ContextNode->getClassConst()
    #7 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/Element.php(57): Phan\AST\UnionTypeVisitor->visitClassConst(Object(ast\Node))
    #8 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/KindVisitorImplementation.php(22): Phan\AST\Visitor\Element->acceptKindVisitor(Object(Phan\AST\UnionTypeVisitor))
    #9 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/UnionTypeVisitor.php(116): Phan\AST\Visitor\KindVisitorImplementation->__invoke(Object(ast\Node))
    #10 /home/oli/.composer/vendor/etsy/phan/src/Phan/Language/UnionType.php(151): Phan\AST\UnionTypeVisitor::unionTypeFromNode(Object(Phan\CodeBase), Object(Phan\Language\Context), Object(ast\Node), true)
    #11 /home/oli/.composer/vendor/etsy/phan/src/Phan/Analysis/BinaryOperatorFlagVisitor.php(181): Phan\Language\UnionType::fromNode(Object(Phan\Language\Context), Object(Phan\CodeBase), Object(ast\Node))
    #12 /home/oli/.composer/vendor/etsy/phan/src/Phan/Analysis/BinaryOperatorFlagVisitor.php(249): Phan\Analysis\BinaryOperatorFlagVisitor->visitBinaryOpCommon(Object(ast\Node))
    #13 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/Element.php(300): Phan\Analysis\BinaryOperatorFlagVisitor->visitBinaryIsEqual(Object(ast\Node))
    #14 /home/oli/.composer/vendor/etsy/phan/src/Phan/Analysis/BinaryOperatorFlagVisitor.php(60): Phan\AST\Visitor\Element->acceptBinaryFlagVisitor(Object(Phan\Analysis\BinaryOperatorFlagVisitor))
    #15 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/UnionTypeVisitor.php(598): Phan\Analysis\BinaryOperatorFlagVisitor->__invoke(Object(ast\Node))
    #16 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/Element.php(45): Phan\AST\UnionTypeVisitor->visitBinaryOp(Object(ast\Node))
    #17 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/KindVisitorImplementation.php(22): Phan\AST\Visitor\Element->acceptKindVisitor(Object(Phan\AST\UnionTypeVisitor))
    #18 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/UnionTypeVisitor.php(116): Phan\AST\Visitor\KindVisitorImplementation->__invoke(Object(ast\Node))
    #19 /home/oli/.composer/vendor/etsy/phan/src/Phan/Language/UnionType.php(151): Phan\AST\UnionTypeVisitor::unionTypeFromNode(Object(Phan\CodeBase), Object(Phan\Language\Context), Object(ast\Node), true)
    #20 /home/oli/.composer/vendor/etsy/phan/src/Phan/Analysis/PreOrderAnalysisVisitor.php(555): Phan\Language\UnionType::fromNode(Object(Phan\Language\Context), Object(Phan\CodeBase), Object(ast\Node))
    #21 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/Element.php(107): Phan\Analysis\PreOrderAnalysisVisitor->visitIfElem(Object(ast\Node))
    #22 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/KindVisitorImplementation.php(22): Phan\AST\Visitor\Element->acceptKindVisitor(Object(Phan\Analysis\PreOrderAnalysisVisitor))
    #23 /home/oli/.composer/vendor/etsy/phan/src/Phan/BlockAnalysisVisitor.php(252): Phan\AST\Visitor\KindVisitorImplementation->__invoke(Object(ast\Node))
    #24 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/Element.php(107): Phan\BlockAnalysisVisitor->visitIfElem(Object(ast\Node))
    #25 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/KindVisitorImplementation.php(22): Phan\AST\Visitor\Element->acceptKindVisitor(Object(Phan\BlockAnalysisVisitor))
    #26 /home/oli/.composer/vendor/etsy/phan/src/Phan/BlockAnalysisVisitor.php(203): Phan\AST\Visitor\KindVisitorImplementation->__invoke(Object(ast\Node))
    #27 /home/oli/.composer/vendor/etsy/phan/src/Phan/BlockAnalysisVisitor.php(401): Phan\BlockAnalysisVisitor->visitBranchedContext(Object(ast\Node))
    #28 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/Element.php(105): Phan\BlockAnalysisVisitor->visitIf(Object(ast\Node))
    #29 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/KindVisitorImplementation.php(22): Phan\AST\Visitor\Element->acceptKindVisitor(Object(Phan\BlockAnalysisVisitor))
    #30 /home/oli/.composer/vendor/etsy/phan/src/Phan/BlockAnalysisVisitor.php(113): Phan\AST\Visitor\KindVisitorImplementation->__invoke(Object(ast\Node))
    #31 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/KindVisitorImplementation.php(312): Phan\BlockAnalysisVisitor->visit(Object(ast\Node))
    #32 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/Element.php(147): Phan\AST\Visitor\KindVisitorImplementation->visitStmtList(Object(ast\Node))
    #33 /home/oli/.composer/vendor/etsy/phan/src/Phan/AST/Visitor/KindVisitorImplementation.php(22): Phan\AST\Visitor\Element->acceptKindVisitor(Object(Phan\BlockAnalysisVisitor))
    #34 /home/oli/.composer/vendor/etsy/phan/src/Phan/Analysis.php(345): Phan\AST\Visitor\KindVisitorImplementation->__invoke(Object(ast\Node))
    #35 /home/oli/.composer/vendor/etsy/phan/src/Phan/Phan.php(162): Phan\Analysis::analyzeFile(Object(Phan\CodeBase), './app/compiled_...')
    #36 /home/oli/.composer/vendor/etsy/phan/src/Phan/ForkPool.php(101): Phan\Phan::Phan\{closure}(142, './app/compiled_...')
    #37 /home/oli/.composer/vendor/etsy/phan/src/Phan/Phan.php(190): Phan\ForkPool->__construct(Array, Object(Closure), Object(Closure), Object(Closure))
    #38 /home/oli/.composer/vendor/etsy/phan/src/phan.php(42): Phan\Phan::analyzeFileList(Object(Phan\CodeBase), Array)
    #39 /home/oli/.composer/vendor/etsy/phan/phan(2): require_once('/home/oli/.comp...')
    #40 {main}
    

    My config file looks like this:

    <?php
    
    use \Phan\Config;
    use \Phan\Issue;
    
    /**
     * This configuration will be read and overlayed on top of the
     * default configuration. Command line arguments will be applied
     * after this file is read.
     *
     * @see src/Phan/Config.php
     * See Config for all configurable options.
     *
     * A Note About Paths
     * ==================
     *
     * Files referenced from this file should be defined as
     *
     * ```
     *   Config::projectPath('relative_path/to/file')
     * ```
     *
     * where the relative path is relative to the root of the
     * project which is defined as either the working directory
     * of the phan executable or a path passed in via the CLI
     * '-d' flag.
     */
    return [
    
            // A list of directories that should be parsed for class and
            // method information. After excluding the directories
            // defined in exclude_analysis_directory_list, the remaining
            // files will be statically analyzed for errors.
            //
            // Thus, both first-party and third-party code being used by
            // your application should be included in this list.
            'directory_list' => ['./'],
    
            // A directory list that defines files that will be excluded
            // from static analysis, but whose class and method
            // information should be included.
            //
            // Generally, you'll want to include the directories for
            // third-party code (such as "vendor/") in this list.
            //
            // n.b.: If you'd like to parse but not analyze 3rd
            //       party code, directories containing that code
            //       should be added to the `directory_list` as
            //       to `excluce_analysis_directory_list`.
        'exclude_analysis_directory_list' => ['vendor', 'node_modules'],
    
            // Backwards Compatibility Checking. This is slow
            // and expensive, but you should consider running
            // it before upgrading your version of PHP to a
            // new version that has backward compatibility
            // breaks.
        'backward_compatibility_checks' => true,
    
    
            // Run a quick version of checks that takes less
            // time at the cost of not running as thorough
            // an analysis. You should consider setting this
            // to true only when you wish you had more issues
            // to fix in your code base.
            'quick_mode' => true,
    
            // If enabled, check all methods that override a
            // parent method to make sure its signature is
            // compatible with the parent's. This check
            // can add quite a bit of time to the analysis.
        'analyze_signature_compatibility' => false,
    
            // If true, missing properties will be created when
            // they are first seen. If false, we'll report an
            // error message if there is an attempt to write
            // to a class property that wasn't explicitly
            // defined.
        'allow_missing_properties' => true,
    
            // If enabled, scalars (int, float, bool, string, null)
            // are treated as if they can cast to each other.
        'scalar_implicit_cast' => true,
    
            // Include a progress bar in the output
        'progress_bar' => true,
    
            // The number of processes to fork off during the analysis
            // phase.
        'processes' => 12,
    
            // Add any issue types (such as 'PhanUndeclaredMethod')
            // here to inhibit them from being reported
        'suppress_issue_types' => [
            'PhanAccessNonStaticToStatic',
            'PhanAccessPropertyPrivate',
            'PhanAccessPropertyProtected',
            'PhanAccessSignatureMismatch',
            'PhanAccessSignatureMismatchInternal',
            'PhanAccessStaticToNonStatic',
            'PhanCompatibleExpressionPHP7',
            'PhanCompatiblePHP7',
            'PhanContextNotObject',
            'PhanDeprecatedClass',
            'PhanDeprecatedFunction',
            'PhanEmptyFile',
            'PhanNonClassMethodCall',
            'PhanNoopArray',
            'PhanNoopClosure',
            'PhanNoopConstant',
            'PhanNoopProperty',
            'PhanNoopVariable',
            'PhanParamReqAfterOpt',
            'PhanParamSpecial1',
            'PhanParamSpecial2',
            'PhanParamSpecial3',
            'PhanParamSpecial4',
            'PhanParamTooFew',
            'PhanParamTooFewInternal',
            'PhanParamTooMany',
            'PhanParamTooManyInternal',
            'PhanParamTypeMismatch',
            'PhanParentlessClass',
            'PhanRedefineClass',
            'PhanRedefineClassInternal',
            'PhanRedefineFunction',
            'PhanRedefineFunctionInternal',
            'PhanSignatureMismatch',
            'PhanSignatureMismatchInternal',
            'PhanStaticCallToNonStatic',
            'PhanSyntaxError',
            'PhanTraitParentReference',
            'PhanTypeArrayOperator',
            'PhanTypeArraySuspicious',
            'PhanTypeComparisonFromArray',
            'PhanTypeComparisonToArray',
            'PhanTypeConversionFromArray',
            'PhanTypeInstantiateAbstract',
            'PhanTypeInstantiateInterface',
            'PhanTypeInvalidLeftOperand',
            'PhanTypeInvalidRightOperand',
            'PhanTypeMismatchArgument',
            'PhanTypeMismatchArgumentInternal',
            'PhanTypeMismatchDefault',
            'PhanTypeMismatchForeach',
            'PhanTypeMismatchProperty',
            'PhanTypeMismatchReturn',
            'PhanTypeMissingReturn',
            'PhanTypeNonVarPassByRef',
            'PhanTypeParentConstructorCalled',
            'PhanTypeVoidAssignment',
            'PhanUnanalyzable',
            'PhanUndeclaredClass',
            'PhanUndeclaredClassCatch',
            'PhanUndeclaredClassConstant',
            'PhanUndeclaredClassInstanceof',
            'PhanUndeclaredClassMethod',
            'PhanUndeclaredClassReference',
            'PhanUndeclaredConstant',
            'PhanUndeclaredExtendedClass',
            'PhanUndeclaredFunction',
            'PhanUndeclaredInterface',
            'PhanUndeclaredMethod',
            'PhanUndeclaredProperty',
            'PhanUndeclaredStaticMethod',
            'PhanUndeclaredStaticProperty',
            'PhanUndeclaredTrait',
            'PhanUndeclaredTypeParameter',
            'PhanUndeclaredTypeProperty',
            'PhanUndeclaredVariable',
            'PhanUnreferencedClass',
            'PhanUnreferencedConstant',
            'PhanUnreferencedMethod',
            'PhanUnreferencedProperty',
            'PhanVariableUseClause',
        ],
    ];
    

    Any ideas? I just want to scan for PHP7 compatibility errors

    bug 
    opened by oligriffiths 13
  • phan daemon, status no_files (version 0.12.1)

    phan daemon, status no_files (version 0.12.1)

    Hello I'm testing out the daemon of phan to try and get faster linting in my editor

    My linting works when using something like this: phan -k ~/.phan/config.php --include-analysis-file-list /private/var/www/xxxx/test.php -i -m checkstyle

    I have put this into a sublime text plugin with sublime linter 4 and it works quite well I'm just trying to see what performance is like with the daemon since the lint can sometimes take a bit of time to complete

    I have copied my config file from ~/.phan/config.php to /private/var/www/xxxx/.phan/config.php because the daemon does not support a custom configuration location

    so I'm running the server with: phan --daemonize-tcp-port 4846 --quick that says: Listening for Phan analysis requests at tcp://127.0.0.1:4846

    and then I'm running: phan_client -l /private/var/www/xxx/test.php but it returns: Invalid response from phan for tcp://127.0.0.1:4846: {"status":"no_files"}

    Why am I getting {"status":"no_files"}?

    question need more info 
    opened by slifin 12
  • Class containing

    Class containing "function match" not found

    This is similar to https://github.com/phan/phan/issues/4750 but about a method called match.

    <?php
    class Foo {
        public function match() {
            return 42;
        }
    }
    $x = new Foo();
    echo $x->match();
    

    This parses and executes fine and without warnings from PHP 5.0.0 to PHP 8.2.0 at https://3v4l.org/anJ94.

    It also analyses and executes with no warnings at https://phan.github.io/demo/ (Phan 5.4.1 and PHP 8.2.0RC5 as of writing).

    But when loaded through a file (minimal repo up at https://github.com/Krinkle/sandbox/tree/phan-less-not-found-match) it produces:

    lib/Less/Cache.php:6 PhanUndeclaredClassMethod Call to method __construct from undeclared class \Less_Parser
    
    opened by Krinkle 1
  • Class not found if file contains brace-less if-statement

    Class not found if file contains brace-less if-statement

    I've recently added a Phan build to https://github.com/wikimedia/less.php, but have encountered quite a lot of noise due to a central class for the project (Less_Parser) seemingly not being found by Phan.

    lib/Less/Cache.php:66 PhanUndeclaredClassMethod Call to method serializeVars from undeclared class \Less_Parser
    lib/Less/Cache.php:144 PhanUndeclaredClassMethod Call to method __construct from undeclared class \Less_Parser
    lib/Less/Cache.php:151 PhanUndeclaredClassMethod Call to method Parse from undeclared class \Less_Parser
    lib/Less/Cache.php:155 PhanUndeclaredClassMethod Call to method ParseFile from undeclared class \Less_Parser
    lib/Less/Cache.php:158 PhanUndeclaredClassMethod Call to method getCss from undeclared class \Less_Parser
    …
    lib/Less/Functions.php:153 PhanUndeclaredClassMethod Call to method round from undeclared class \Less_Parser
    lib/Less/Functions.php:162 PhanUndeclaredClassMethod Call to method round from undeclared class \Less_Parser
    …
    

    And so on. After a lot of trial and error, I narrowed it down to the following 3 lines of code in two PHP files with the latest Phan version, and little to no config.

    	"require-dev": {
    		"phan/phan": "5.4.1"
    	},
    	"scripts": {
    		"phan": "phan --allow-polyfill-parser --no-progress-bar"
    	},
    
    <?php
    return [
    	'directory_list' => ['lib/',],
    	'exclude_analysis_directory_list' => ['vendor/'],
    	'plugins' => [],
    ];
    
    <?php
    class Less_Parser {
    	public function __construct() {
    	}
    
    	/**
    	 * @param string $name
    	 */
    	public function unregisterFunction( $name ) {
    		if ( isset( $this->env->functions[$name] ) ) # Add braces here and the class is now found
    			unset( $this->env->functions[$name] );
    	}
    }
    
    class Less_Cache {
    	public static function Get() {
    		$lessvars = Less_Parser::serializeVars();
    	}
    }
    

    I've uploaded it at https://github.com/Krinkle/sandbox/tree/phan-less-not-found for easy reproduction. Using PHP 8.2.0 from Homebrew on macOS (as well as on using PHP 7.4 on Ubuntu 20 via GitHub Actions originally), composer install + composer phan leads to:

    lib/Less/Cache.php:6 PhanUndeclaredClassMethod Call to method serializeVars from undeclared class \Less_Parser
    

    It appears this bug may be specific to the way Phan reads files from disk. When I paste the same minimal code at https://phan.github.io/demo/, the issue does not happen.

    After an hour of debugging and narrowing down, I found that the unregisterFunction function above was making the class appear undefined to Phan. More specifically, the lack of braces around the if-statement. I've boldly titled the issue as such, but it may very well have a deeper cause that merely happens to manifest around braces. Happy to hear what I've done wrong, if anything! 🙂

    opened by Krinkle 0
  • Phan crashes with

    Phan crashes with "Implicit conversion from float 1.2 to int loses precision" under php8.1 in AssignmentVisitor.php

    Using phan/phan 5.4.1 under php81. I am getting a fatal error of "Implicit conversion from float 1.2 to int loses precision"

    PHP code:

    <?php
    
    try {
    	$dummy = $list[1.2];
    	$this->fail( 'Expected exception not thrown' );
    } catch ( InvalidArgumentException $ex ) {
    	$this->assertSame( 'Offset must be an integer.', $ex->getMessage() );
    }
    
    try {
    	$list[1.2] = $value6;
    	$this->fail( 'Expected exception not thrown' );
    } catch ( InvalidArgumentException $ex ) {
    	$this->assertSame( 'Offset must be an integer.', $ex->getMessage() );
    }
    
    The following error occurs:
    vendor\phan\phan\src\Phan\Analysis\AssignmentVisitor.php:881 [8192] Implicit conversion from float 1.2 to int loses precision
    (Phan 5.4.1 crashed when parsing/analyzing '....')
    More details:
    #2: Phan\Analysis\AssignmentVisitor->visitDim() called at [vendor\phan\phan\src\Phan\AST\Visitor\KindVisitorImplementation.php:35] Args: [ast\Node({"kind":512,"flags":1879048192,"lineno":11,"children":{"expr":{"kind":256,"flags":1610612736,"lineno":11,"children":{"name":"list"},"taint":{}},"dim":1.2},"taint":{}})]
    #3: Phan\AST\Visitor\KindVisitorImplementation->__invoke() called at [vendor\phan\phan\src\Phan\Analysis\PostOrderAnalysisVisitor.php:174] Args: [ast\Node({"kind":512,"flags":1879048192,"lineno":11,"children":{"expr":{"kind":256,"flags":1610612736,"lineno":11,"children":{"name":"list"},"taint":{}},"dim":1.2},"taint":{}})]
    

    When looking at 8dcca001d15563ca12000cdfccd6f85c192631a3 the fix seems simple by casting to string (it passed after that), but that would miss the "filter_var" part, I am not sure if that is relevant here.

             } elseif (\is_scalar($dim_node)) {
    -            $dim_value = $dim_node;
    +            $dim_value = is_int( $dim_node ) ? $dim_node : (string)$dim_node;
                 $dim_type = Type::fromObject($dim_node)->asRealUnionType();
    
    opened by umherirrender 0
  • updated interfaces in php 8.1

    updated interfaces in php 8.1

    The interfaces SessionHandlerInterface and SessionUpdateTimestampHandlerInterface now implement the real types, so e.g. the signature is public function validateId(string $sessID): bool, public function open(string $savePath, string $sessName): string, ....

    unfortuanately the documentation does not show when this is changed.

    opened by mokraemer 0
  • SleepCheckerPlugin does not recognize spread operator

    SleepCheckerPlugin does not recognize spread operator

    Enable the plugin, have to classes:

    class A{
    public string $text="x";
    function __sleep(): array{
    		return ['text'];
    	}
    }
    class B extends A{
    public int $i=3;
    
    function __sleep(): array{
    		return [...parent::__sleep(), 'i'];
    	}
    }
    

    phan crashes somewhere like here: (Phan 5.4.1 crashed when parsing/analyzing 'test.php') More details: #2: Phan\AST\ContextNode->getEquivalentPHPArrayElements() ....

    opened by mokraemer 0
  • phan flags iterables as not compatible with iterator_to_array

    phan flags iterables as not compatible with iterator_to_array

    Phan is flagging arguments of type iterable as not compatible with iterator_to_array.

    Iterable is a builtin type which is synonymous with \Traversable|array. https://www.php.net/manual/en/language.types.iterable.php

    iterator_to_array takes a \Traversable|array as an argument, but phan doesn't recognize them as compatible. https://www.php.net/manual/en/function.iterator-to-array.php

    To reproduce:

    function doSomething(iterable $foo) {
        $bar = iterator_to_array($foo);
        return $bar;
    }
    

    gives the error:

    src/test.php:3 PhanTypeMismatchArgumentInternal Argument 1 ($iterator) is $foo of type iterable but \iterator_to_array() takes \Traversable
    

    Using php 8.0.24, phan 5.4.1

    opened by driusan 0
Releases(5.4.1)
  • 5.4.1(Aug 26, 2022)

    New Features(Analysis):

    • Support parsing php 8.2's disjunctive normal form types (e.g. A|(B&C) (https://wiki.php.net/rfc/dnf_types). (#4699)
    • Support php 8.2 class constants on trait RFC. (#4687) Emit PhanCompatibleTraitConstant when using constants on traits with a minimum_target_php_version below '8.2' Emit PhanAccessClassConstantOfTraitDirectly when directly referencing the class constant on the trait declaration.
    • Emit PhanTypeModifyImmutableObjectProperty for PHP 8.1 readonly properties when modified anywhere outside of the declaring class's scope. (#4710)

    Miscellaneous:

    • Allow array_filter $callback to be null (#4715)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.83 MB)
    phan.phar.asc(593 bytes)
  • 5.4.0(Aug 9, 2022)

    New Features(CLI, Configs):

    • Add tool/analyze_phpt to analyze phpt files. See https://www.phpinternalsbook.com/tests/phpt_file_structure.html

    New Features(Analysis):

    • Support php 8.2's true type (https://wiki.php.net/rfc/true-type). Emit PhanCompatTrueType when true is used when minimum_target_php_version is less than 8.2.
    • Emit PhanCompatStandaloneType instead of PhanInvalidNode for uses of null/false as real standalone types to support php 8.2 https://wiki.php.net/rfc/null-false-standalone-types (Not emitted when minimum_target_php_version is 8.2 or higher)
    • Improve support for php 8.2 readonly classes and php 8.1 readonly properties

    Bug fixes:

    • Fix php 8.2.0-dev deprecation notice for ast\Node when running Phan in php 5.2.0 with the polyfill instead of the native php-ast version.
    • Fix DuplicateArrayKeyPlugin "Implicit conversion from float ... to int" warning causing crash in php 8.1 (#4666)
    • Fix slow memory leak of reference cycles in the language server - enable garbage collection for the Phan daemon/language server consistently. (#4665) (This fix is only enabled in php 7.3+ when using pcntl, the pcntl fallback already re-enabled garbage collection. php 7.3 improved the garbage collection efficiency for large collections of objects.)
    • Move PhanGenericConstructorTypes warning to the class inheriting a constructor if needed (#4675)
    • Fix crash when combining types for null and an array with PHP_INT_MAX as a key (#4688)
    • Fix incorrect type inference for arrays with keys that were invalid UTF-8 (#4688)
    • Fix error due to deprecation notice running Phan in php 8.2 due to use of "${}" string interpolation (#4692)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.85 MB)
    phan.phar.asc(593 bytes)
  • 5.3.2(Feb 1, 2022)

    New Features(Analysis):

    • Use intersection type of original variable value and array elements when inferring type of $var in in_array($var, $array) instead of just the type of the array elements (#4630)
    • Treat type of concatenation of one or more non-real strings as a phpdoc(non-real) string with the real type string. (#4635)
    • In phan --init, allow inferring php 8.1 as the target php version in the generated config file. (#4655)

    Maintenance:

    • Allow installing xdebug-handler version ^3.0 (#4639)
    • Allow installing symfony/console version ^6.0 (#4642)

    Bug fixes:

    • Fix AST download link for PHP 8.0+ for Windows (#4645)

    • Fix dead code detection for PHP 8.0 non-capturing catch statements. (#4633) This should still analyze the catch body even if there is no caught exception variable.

    • Ignore phpdoc comment tags that don't start at the start of a line of the doc comment (* @sometag) or aren't an inline tag (* something {@sometag}). (#4640) See https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/internal.html and https://docs.phpdoc.org/2.9/guides/docblocks.html

      E.g. * This is not @abstract. is no longer treated as an abstract method.

    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.79 MB)
    phan.phar.asc(593 bytes)
  • 5.3.1(Dec 14, 2021)

    New Features(Analysis):

    • Emit PhanDeprecatedPartiallySupportedCallable for functions that work with call_user_func($expr) but not $expr(). The literal strings 'self', 'parent', and 'static' in 'self::methodName' or ['self', 'methodName'] in callables were deprecated in PHP 8.2.
    • Emit PhanDeprecatedPartiallySupportedCallableAlternateScope for uses of callables such as [new SubClass(), 'Base::method'] specifying an alternate scope.
    • Make pass-by-ref vars result in a merged union type, not an overwritten one. (#4602)

    Plugins:

    • Update format string message for PhanPluginUnknownClosureParamType and PhanPluginUnknownFunctionParamType.

    Bug fixes:

    • Avoid crashing when running in PHP 8.2+ after php 8.2 deprecated dynamic(undeclared) properties on classes without #[AllowDynamicProperties].
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.77 MB)
    phan.phar.asc(593 bytes)
  • 5.3.0(Nov 13, 2021)

    New Features(Analysis):

    • Fix false positive PhanPossiblyUndeclaredVariable warning when a try block unconditionally returns/throws/exits (#4419)

    • Fix false positive warnings when analyzing enums, infer that automatically generated methods of enums exist. (#4313)

    • Properly resolve template type when getIterator returns an Iterator that includes a template. (#4556)

    • Fix false positives such as PhanTypeMismatchArgumentNullable analyzing recursive call with parameter set to literal, without real type information. (#4550) (e.g. function ($retry = true) { if ($retry) {/*...*/} some_call_using_retry($retry); })

    • Properly detect PhanUnusedVariable in try-catch where catch always rethrows. (#4567)

    • Make read-only/write-only property detection more accurate for assignment operations (e.g. +=, ??=) and increment/decrement operations. (#4570)

    • Improve estimates of array sizes when analyzing calls that unpack values, based on the inferred real type set. (#4577)

    • Infer that variadic parameters can have string keys (as of php 8.0) (#4579)

    • Emit PhanParamTooFewUnpack and PhanParamTooFewInternalUnpack to indicate when argument unpacking may provide too few arguments to the called function. (#4577)

    • Support the non-standard @no-named-arguments PHPDoc comment on function-likes. (#4580, #4152) Treat variadic parameters as list types when this annotation is used, warn about unpacking string arguments or explicitly passing named arguments to functions using this declaration.

    • Warn about argument unpacking that may pass strings to internal functions (e.g. var_dump(...['a' => 'unsupported'])) (#4579) New issue types: PhanSuspiciousNamedArgumentVariadicInternalUnpack

    • Support @phan-type AliasName=UnionType annotation in inline strings or element comments (#4562)

      These aliases will apply to remaining statements in the current top-level namespace blocks, similar to use statements, but can also be defined in methods and apply to subsequent methods.

      This can be of use in avoiding repetition of phpdoc for long type definitions.

      // Alternate inline string version to work around php-ast limitations
      '@phan-type UserData = array{name: string, id: int, createdAt: DateTime}';
      
      /**
       * @type-alias UserData = array{name: string, id: int, createdAt: DateTime}
       * (applies to phpdoc in this and all subsequent AST nodes in the namespace block)
       */
      class ExampleElementWithPHPDoc {
          /**
           * @param UserData[] $users
           * @return list<UserData>
           */
          public function filterUsers(array $values): array { /* ... */ }
      }
      
      // The UserData alias is still defined and can be used in other statements
      
      namespace XYZ;
      // The UserData alias is no longer defined in the new namespace block.
      
    • When analyzing calls that modify variables as pass by reference, merge old types with existing types to account for possibility of branches or early returns (#4602)

    Plugins:

    • Warn about non-empty try statements that are unlikely to throw in EmptyStatementListPlugin (#4555)
    • Warn in AlwaysReturnPlugin about functions/methods with no return type that have at least one return statement with an expression, but may fall through to the end of the function body without an explicit return (#4587)

    Bug fixes:

    • Fix off-by-one error when inferring from comparison conditions such as count($arr) > 0 and count($arr) >= 1 that the array is non-empty. (#4551)
    • Fix checking file path suppressed by baseline (with /) on windows (#4149)
    • Fix crash when inferring type of array access for scalar other than int/string (e.g. $arr[true]) (#4573)
    • Properly read --processes N CLI flag before checking if phan should restart without grpc (#4608)

    Maintenance:

    • Account for a few PHP 8.0 signature changes for PDOStatement::fetchAll and Phar methods. (#4569)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.70 MB)
    phan.phar.asc(593 bytes)
  • 5.2.1(Sep 15, 2021)

    New Features:

    • Improve analysis of conditions detecting the empty/non-empty array. (#4523) E.g. support if ($x === []) {...} else {...}, if (count($x) > 0) {...} else {...}, etc.
    • Raise severity of PhanTypeNonVarPassByRef to critical. It throws an Error in php 8.0+. (#3830)
    • Infer from conditions such as in_array($var, $array, true) that $array is a non-empty array and that $var is of a type found in the elements of $array. (#2511)

    Plugins:

    • Emit a proper warning when InvokePHPNativeSyntaxCheckPlugin is passed a path to a php binary that is missing or invalid (or if the syntax check crashed). (#4116) Previously, Phan would crash with an error such as fwrite(): write of 8196 bytes failed with errno=32 Broken pipe
    • Fix false positive PhanPluginMoreSpecificActualReturnType for phpdoc array shape return type and returned generic array. (#4531)

    Bug fixes:

    • Fix type inference logic that was looking for array specializations rather than array or any array subtype (#4512)

    • Fix false positive PhanUnreferencedClosure/PhanUnreferencedFunction seen when a closure/function name was passed to a function such as uasort that already had a plugin analyzing calls of the closure. (#4090, #4519)

    • Fix false positive/negative PhanTypeMissingReturn* instances. (#4537)

      The check was wrong and should have been checking for a statement list that throws/exits. Return statements can be omitted if a function unconditionally exits.

      Also, check for the real never return type when emitting issues

    • Fix false positive PhanPossiblyUndefinedGlobalVariable* instance when global $var is used within a conditional. (#4539)

    • Fix false positive PhanPluginRedundantAssignmentInLoop instance when a variable is modified in a catch statement with a break/continue. (#4542)

    • Fix some incorrect line numbers in some plugin issues.

    • Fix crash seen when parsing intersection types containing union types such as non-empty-array&array<'a'|'b'> (#4544)

    Maintenance:

    • Fix old return type signature for get_headers (#3273)
    • Print instructions on how to upgrade php-ast to 1.0.11+ if an outdated version is installed. (#4532)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.64 MB)
    phan.phar.asc(593 bytes)
  • 5.2.0(Aug 26, 2021)

    Plugins

    • Add AddNeverReturnTypePlugin`` which will suggest adding a phpdoc return type of@return never`. (#4468)

    Bug fixes:

    • When using the polyfill parser, properly parse nullable class property declarations as nullable. (#4492)
    • Don't emit PhanIncompatibleRealPropertyType for private base property. (#4426)
    • Fix false positive where a method overriding an existing method could be treated as having overrides. (#4502)
    • Consistently support numeric-string in all phpdoc
    • Fix false positive PhanTypeMismatchPropertyDefaultReal warning for literal integer and float typed property. (#4507)
    • Fix false positive warnings such as PhanImpossibleTypeComparison about string subtypes not casting to other string subtypes (#4514)

    Maintenance:

    • Change internal representation of FunctionSignatureMap delta files.
    • Add a new exit status bit flag to BlockExitStatusChecker to indicate that a function will exit or infinitely loop (STATUS_NORETURN) (#4468)
    • Internally represent the base function map using php 8.0 signatures instead of php 7.3 - applying deltas backwards has the same result (#4478)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.63 MB)
    phan.phar.asc(593 bytes)
  • 4.1.0(Aug 10, 2021)

    Maintenance:

    • Recommend using Phan 5 when analyzing code (#4487)
    • Mention that Phan 5 has been released in --help, --version, and crash reports (#4487) The environment variable PHAN_SUPPRESS_PHP_UPGRADE_NOTICE=1 can be set to disable this notice.
    • Warn if attempting to execute Phan 4.x with PHP 8.1 (Phan 5 fully supports all PHP 8.1 features, notably intersection types)
    • Upgrade from tolerant-php-parser 0.0.23 to 0.1.1
    • Backport some changes from Phan 5 for php 8.1 first-class callable conversion (...) and avoid crashing when parsing intersection types. Note that Phan 5 must be used instead to actually support intersection types; intersection types are not part of Phan 4's type system.
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.47 MB)
    phan.phar.asc(593 bytes)
  • 5.1.0(Aug 7, 2021)

  • 5.0.0(Aug 1, 2021)

    If you are migrating from Phan 4, it may be useful to set up or update a Phan baseline file to catch issues such as nullable type mismatches. https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base has other advice on setting up suppressions. For example, Phan is now more consistently warning about nullable arguments (i.e. both \X|null and ?\X) in a few cases where it may have not warned about passing \X|null to a function that expects a non-null type.

    If you are using plugins for Phan 4 that are not part of Phan itself, they may have issues in Phan 5 due to additional required parameters being added to many of Phan's methods.

    See the changelog for other changes in the previous alpha releases: https://github.com/phan/phan/blob/5.0.0/NEWS.md

    New Features (Analysis):

    • Warn about implicitly nullable parameter intersection types (function(A&B $paramName = null)) being a compile error. New issue type: PhanTypeMismatchDefaultIntersection

    • Emit PhanTypeMismatchArgumentSuperType instead of PhanTypeMismatchArgument when passing in an object supertype (e.g. ancestor class) of an object instead of a subtype. Emit PhanTypeMismatchReturnSuperType instead of PhanTypeMismatchReturn when returning an object supertype (e.g. ancestor class) of an object instead of a subtype.

      Phan 5 starts warning about ancestor classes being incompatible argument or return types in cases where it previously allowed it. (#4413)

    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.60 MB)
    phan.phar.asc(593 bytes)
  • 5.0.0a4(Jul 24, 2021)

    This is the unstable branch for alpha releases of Phan 5. Planned/remaining work is described in https://github.com/phan/phan/issues/4413

    If you are migrating from Phan 4, it may be useful to set up or update a Phan baseline file to catch issues such as nullable type mismatches. https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base has other advice on setting up suppressions. For example, Phan is now more consistently warning about nullable arguments (i.e. both \X|null and ?\X) in a few cases where it may have not warned about passing \X|null to a function that expects a non-null type.

    If you are using plugins that are not part of Phan itself, they may have issues in Phan 5 due to additional required methods being added to many of Phan's methods.

    New Features (Analysis):

    • Use the enum class declaration type (int, string, or absent) from AST version 85 to check if enum cases are valid. (#4313) New issue types: PhanSyntaxEnumCaseExpectedValue, PhanSyntaxEnumCaseUnexpectedValue, PhanTypeUnexpectedEnumCaseType

    Backwards incompatible changes:

    • Bump the minimum required AST version from 80 to 85 (Required to analyze php 8.1 enum classes - 'type' was added in AST version 85).
    • In php 8.1, require php-ast 1.0.14 to natively parse AST version 85.

    Maintenance:

    • Upgrade tolerant-php-parser from 0.1.0 to 0.1.1 to prepare to support new php syntax in the polyfill/fallback parser. (#4449)

    Bug fixes:

    • Fix extraction of reflection attribute target type bitmask from internal attributes such as PHP 8.1's ReturnTypeWillChange
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.59 MB)
    phan.phar.asc(593 bytes)
  • 5.0.0a3(Jul 15, 2021)

    July 15, 2021, Phan 5.0.0a3

    Phan 5 introduces support for intersection types, and improves the accuracy of type casting checks and type inference to catch more issues.

    This is the unstable branch for alpha releases of Phan 5. Planned/remaining work is described in https://github.com/phan/phan/issues/4413

    If you are migrating from Phan 4, it may be useful to set up or update a Phan baseline file to catch issues such as nullable type mismatches. https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base has other advice on setting up suppressions. For example, Phan is now more consistently warning about nullable arguments (i.e. both \X|null and ?\X) in a few cases where it may have not warned about passing \X|null to a function that expects a non-null type.

    If you are using plugins that are not part of Phan itself, they may have issues in Phan 5 due to additional required methods being added to many of Phan's methods.

    New Features (Analysis):

    • Support parsing php 8.1 intersection types in php-ast 1.0.13+ (#4469) (not yet supported in polyfill)
    • Support parsing php 8.1 first-class callable syntax in unreleased php-ast version (#4464)
    • Support parsing php 8.1 readonly property modifier (#4463)
    • Support allowing new expressions in php 8.1 readonly property modifier (#4460)
    • Emit PhanTypeInvalidArrayKey and PhanTypeInvalidArrayKeyValue for invalid array key literal types or values.
    • Fix false positive PhanTypeMissingReturn/PhanPluginAlwaysReturnMethod for method with phpdoc return type of @return never
    • Warn about direct access to static methods or properties on traits (instead of classes using those methods/properties) being deprecated in php 8.1 (#4396)
    • Add Stringable to allowed types for sprintf variadic arguments. This currently requires explicitly implementing Stringable. (#4466)

    Bug fixes:

    • Fix a crash when analyzing array literals with invalid key literal values in php 8.1.
    • Fix a crash due to deprecation notices for accessing trait methods/properties directly in php 8.1
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.58 MB)
    phan.phar.asc(593 bytes)
  • 5.0.0a2(Jun 26, 2021)

    Jun 26 2021, Phan 5.0.0a2

    Phan 5 introduces support for intersection types, and improves the accuracy of type casting checks and type inference to catch more issues.

    This is the unstable branch for alpha releases of Phan 5. Planned/remaining work is described in https://github.com/phan/phan/issues/4413

    If you are migrating from Phan 4, it may be useful to set up or update a Phan baseline file to catch issues such as nullable type mismatches. https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base has other advice on setting up suppressions. For example, Phan is now more consistently warning about nullable arguments (i.e. both \X|null and ?\X) in a few cases where it may have not warned about passing \X|null to a function that expects a non-null type.

    If you are using plugins that are not part of Phan itself, they may have issues in Phan 5 due to additional required methods being added to many of Phan's methods.

    New Features (Analysis):

    • Improve accuracy of checks for weak type overlap for redundant condition warnings on <=
    • Emit PhanAccessOverridesFinalConstant when overriding a final class constant. (#4436)
    • Emit PhanCompatibleFinalClassConstant if class constants have the final modifier in codebases supporting a minimum target php version older than 8.1 (#4436)
    • Analyze class constants declared in interfaces as if they were final in php versions prior to 8.1. (#4436)
    • Warn about using $this or superglobals as a parameter or closure use. (#4336)

    New Features (CLI)

    • Use var_representation/polyfill for generating representations of values in issue messages.

    Maintenance:

    • Upgrade tolerant-php-parser from ^0.0.23 to ^0.1.0 to prepare to support new php syntax in the polyfill/fallback parser. (#4449)

    Bug fixes:

    • Properly warn about referencing $this from a static fn declared in an instance method. (#4336)
    • Fix a crash getting template parameters of intersection types
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.55 MB)
    phan.phar.asc(593 bytes)
  • 4.0.7(Jun 26, 2021)

    The Phan 5 release line (currently in alpha) will support PHP 8.1 syntax and new features such as intersection types

    Language Server/Daemon mode:

    • Fix an uncaught exception sometimes seen checking for issue suppressions when pcntl is unavailable.

    Maintenance:

    • Expand allowed netresearch/jsonmapper version ranges to include ^4.0 for php 8.1 support.
    • Update dependencies in composer.lock for compatibility with php 8.1 in published phar files.

    Bug fixes:

    • Don't emit PhanCompatibleNonCapturingCatch when minimum_target_php_version is '8.0' or newer. (#4433)

    • Stop ignoring @return null and @param null $paramName in phpdoc. (#4453)

      Stop special casing @param null now that Phan allows many other literal types in param types.

    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.45 MB)
    phan.phar.asc(593 bytes)
  • 5.0.0a1(May 30, 2021)

    May 30 2021, Phan 5.0.0a1

    Phan 5 introduces support for intersection types, and improves the accuracy of type casting checks and type inference to catch more issues.

    This is the unstable branch for alpha releases of Phan 5. Planned/remaining work is described in https://github.com/phan/phan/issues/4413

    If you are migrating from Phan 4, it may be useful to set up or update a Phan baseline file to catch issues such as nullable type mismatches. https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base has other advice on setting up suppressions. For example, Phan is now more consistently warning about nullable arguments (i.e. both \X|null and ?\X) in a few cases where it may have not warned about passing \X|null to a function that expects a non-null type.

    If you are using plugins that are not part of Phan itself, they may have issues in Phan 5 due to additional required methods being added to many of Phan's methods.

    New Features (Analysis):

    • Support parsing intersection types in phpdoc and checking if intersection types satisfy type comparisons
    • Support inferring intersection types from conditions such as instanceof
    • Warn about impossible type combinations in phpdoc intersection types. New issue types: PhanImpossibleIntersectionType
    • Improve type checking precision for whether a type can cast to another type.
    • Improve precision of checking if a type is a subtype of another type.
    • Split out warnings about possibly invalid types for property access (non-object) and possibly invalid classes for property access New issue types: PhanPossiblyUndeclaredPropertyOfClass
    • Also check for partially invalid expressions for instance properties during assignment (PhanPossiblyUndeclaredProperty*)
    • Treat @template-covariant T as an alias of @template T - Previously, that tag was not parsed and T would be treated like a (probably undeclared) classlike name. (#4432)

    Bug fixes:

    • Fix wrong expression in issue message for PhanPossiblyNullTypeMismatchProperty (#4427)

    Breaking Changes:

    • Many internal methods now require a mandatory CodeBase instance. This will affect third party plugins.
    • Remove --language-server-min-diagnostic-delay-ms.
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.47 MB)
    phan.phar.asc(593 bytes)
  • 4.0.6(May 19, 2021)

    New Features (Analysis):

    • Partially support php 8.1 enums (#4313) (infer the real type is the class type, that they cannot be instantiated, that enum values cannot be reused, and that class constants will exist for enum cases)

      New issue types: PhanReusedEnumCaseValue, PhanTypeInstantiateEnum, PhanTypeInvalidEnumCaseType, PhanSyntaxInconsistentEnum, PhanInstanceMethodWithNoEnumCases, PhanInstanceMethodWithNoEnumCases, PhanEnumCannotHaveProperties, PhanUnreferencedEnumCase, PhanEnumForbiddenMagicMethod.

    • Support php 7.4 covariant return types and contravariant parameter types when the configured or inferred minimum_target_php_version is '7.4' or newer (#3795)

    • Add initial support for the php 8.1 never type (in real return types and phpdoc). (#4380) Also add support for the phpdoc aliases no-return, never-return, and never-returns

    • Support casting iterable<K, V> to Traversable<K, V> with is_object or !is_array checks

    • Detect more types of expressions that never return when inferring types (e.g. when analyzing ?:, ?? operators)

    • Use php 8.1's tentative return types from reflection (hasTentativeReturnType, getTentativeReturnType) to assume real return types of internal functions/methods (#4400)

      This can be disabled by setting use_tentative_return_type to false (e.g. when using subclasses of internal classes that return incompatible types).

    • Warn about modifying properties of classes that are immutable at runtime (enums, internal classes such as \Closure and \WeakRef, etc.) (#4313) New issue type: PhanTypeModifyImmutableObjectProperty

    Dead code detection:

    • Infer that functions with a return type of never (or phpdoc aliases such as no-return) are unreachable when performing control flow analysis. This can be disabled by setting dead_code_detection_treat_never_type_as_unreachable to false

      Note that control flow is only affected when UseReturnValuePlugin is enabled.

    Plugins:

    • In UseReturnValuePlugin, also start warning about when using the result of an expression that evaluates to never New issue types: PhanUseReturnValueOfNever

    Bug fixes:

    • As part of the work on php 7.4 contravariant parameter types, don't automatically inherit inferred parameter types from ancestor classlikes when (1) there is no @param tag with a type for the parameter on the overriding method and (2) the ancestor parameter types are a subtype of the real parameter types unless

      1. @inheritDoc is used.
      2. This is a generic array type such as array<string,mixed> that is a specialization of an array type. If you want to indicate that the overriding method can be any array type, add @param array $paramName.
    • Change composer.json dependency on composer/xdebug-handler from ^2.0 to ^1.1|2.0 to avoid conflicting with other libraries or applications that depend on xdebug-handler 1.x (#4382)

    • Support parsing multiple declare directives in the polyfill/fallback parser (#4160)

    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.42 MB)
    phan.phar.asc(593 bytes)
  • 4.0.5(Apr 29, 2021)

    New Features (Analysis):

    • Fix handling of some redundant condition checks involving non-null-mixed and null (#4388, #4391)
    • Emit PhanCompatibleSerializeInterfaceDeprecated when a class implements Serializable without also implementing the __serialize and __unserialize methods as well. (#4387) PHP 8.1 deprecates the Serializable interface when __serialize and __unserialize aren't also implemented to be used instead of serialize/unserialize.

    Maintenance:

    • Warn about running phan with multiple processes without pcntl before the analysis phase starts.
    • Start implementing __serialize/__unserialize in Phan itself in places that use Serializable.
    • Use different static variables in different subclasses of Phan\Language\Type to account for changes in static variable inheritance in php 8.1. (#4379)

    Bug fixes:

    • Allow ?T to be used in parameter/property types with @template T (#4388)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.36 MB)
    phan.phar.asc(593 bytes)
  • 4.0.4(Apr 14, 2021)

    New Features (CLI, Config):

    • Support --doc-comment flag on tool/make_stubs to emit the doc comments Phan is using for internal elements along with the stubs. (these are the doc comments Phan would use for hover text in the language server)
    • Allow target_php_version and minimum_target_php_version to be 8.1 or newer.

    New Features (Analysis):

    • Support the php 8.1 array unpacking with string keys RFC (#4358). Don't emit warnings about array unpacking with string keys when minimum_target_php_version is '8.1' or newer.
    • Support php 8.1 array_is_list(array $array): bool conditional and its negation. (#4348)
    • Fix some false positive issues when trying to eagerly evaluate expressions without emitting issues (#4377)

    Bug fixes:

    • Fix crash analyzing union type in trait (#4383)

    Maintenance:

    • Update from xdebug-handler 1.x to 2.0.0 to support Xdebug 3 (#4382)

    Plugins:

    • Cache plugin instances in ConfigPluginSet. This is useful for unit testing stateless plugins which declare the plugin class in the same file returning the plugin instance. (#4352)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.35 MB)
    phan.phar.asc(593 bytes)
  • 4.0.3(Jan 30, 2021)

    New Features:

    • Support inferring iterable value types/keys from getIterator returning an ordinary Iterator<X> (previously only inferred types for subclasses of Iterator)

    Bug fixes:

    • Fix crash when rendering [...$x] in an issue message (#4351)
    • Infer that if ($x) converts non-null-mixed to non-empty-mixed
    • Fix false positive warning case for PhanParamSignaturePHPDocMismatchParamType when a phpdoc parameter has a default value (#4357)
    • Properly warn about accessing a private class constant as self::CONST_NAME from inside of a subclass of the constant's declaring class (#4360)
    • Properly infer allow_method_param_type_widening from minimum_target_php_version to avoid false positive PhanParamSignatureRealMismatchHasNoParamType.
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.31 MB)
    phan.phar.asc(593 bytes)
  • 4.0.2(Jan 9, 2021)

    New Features:

    • Improve suggestions for PhanUndeclaredThis inside of static methods/closures (#4336)

    Language Server/Daemon mode:

    • Properly generate code completions for :: and -> at the end of a line on files using Windows line endings(\r\n) instead of Unix newlines(\n) on any OS (#4345) Previously, those were not completed.

    Bug fixes:

    • Fix false positive PhanParamSignatureMismatch for variadic overriding a function using func_get_args() (#4340)
    • Don't emit PhanTypeNoPropertiesForeach for the Countable interface on its own. (#4342)
    • Fix false positive type mismatch warning for casts from callable-object/callable-array/callable-string to function(paramtypes):returntype (#4343)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.31 MB)
    phan.phar.asc(593 bytes)
  • 4.0.1(Dec 31, 2020)

  • 3.2.10(Dec 31, 2020)

    Phan 4 is out (requires php-ast 1.0.7+ or the polyfill to run, and uses AST version 80). That release line will contain all of Phan's new features, bug fixes, and crash fixes.

    The Phan 3.x release line uses php-ast's AST version 70 and supports the analysis of all PHP 8.0 syntax except attributes (when run with PHP 8).

    Maintenance:

    • Recommend using Phan 4 when analyzing code as a line printed to STDERR. (#4189)
    • Mention that Phan 4 has been released in --help, --version, and crash reports. (#4189) The environment variable PHAN_SUPPRESS_PHP_UPGRADE_NOTICE=1 can be set to disable this notice.
    • Warn if attempting to execute Phan 3.x with PHP 8.1-dev or newer (A future release of Phan 4+ will fully support 8.1) PHP 8.1 may contain changes to syntax that are unsupported by Phan 3 or the native/polyfill parsers.

    Bug fixes

    • Fix false positive PhanPossiblyFalseTypeReturn with strict type checking for substr when target php version is 8.0+ (#4335)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.26 MB)
    phan.phar.asc(593 bytes)
  • 4.0.0(Dec 26, 2020)

    • Merge changes from Phan 3.2.9.
    • Relax minimum php-ast restrictions when polyfill is used for Phan 4.
    • Fix conflicting class constant seen in polyfill when php-ast 1.0.6 was installed.

    The Phan v4 release line has the following changes from Phan 3:

    • Bump the minimum required AST version from 70 to 80 (Required to analyze php 8.0 attributes - the rest of the php 8.0 syntax changes are supported in both Phan 3 and Phan 4). A few third party plugins may be affected by the increase of the AST version.
    • Supports analyzing whether #[...] attributes are used properly when run with PHP 8.0+
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.29 MB)
    phan.phar.asc(593 bytes)
  • 3.2.9(Dec 26, 2020)

    The Phan 3.x release line uses php-ast's AST version 70 and supports the analysis of all PHP 8.0 syntax except attributes (when run with PHP 8). The planned 4.x release line will use AST version 80 and require php-ast 1.0.10+ in order to parse/analyze PHP 8.0's #[] attributes

    Bug fixes:

    • Fix a few parameter names for issue messages (#4316)
    • Fix bug that could cause Phan not to warn about SomeClassWithoutConstruct::__construct in some edge cases. (#4323)
    • Properly infer self is referring to the current object context even when the object context is unknown in namespaces. (#4070)

    Deprecations:

    • Emit a deprecation notice when running this in PHP 7 and php-ast < 1.0.7. (#4189) This can be suppressed by setting the environment variable PHAN_SUPPRESS_AST_DEPRECATION=1.
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.25 MB)
    phan.phar.asc(593 bytes)
  • 4.0.0-RC2(Dec 23, 2020)

    The Phan v4 release line has the following changes from Phan 3:

    • Bump the minimum required AST version from 70 to 80 (Required to analyze php 8.0 attributes - the rest of the php 8.0 syntax changes are supported in both Phan 3 and Phan 4). A few third party plugins may be affected by the increase of the AST version.
    • Supports analyzing whether #[...] attributes are used properly when run with PHP 8.0+

    Changes

    Merge changes from Phan 3.2.8

    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.29 MB)
    phan.phar.asc(593 bytes)
  • 3.2.8(Dec 23, 2020)

    The Phan 3.x release line uses php-ast's AST version 70 and supports the analysis of all PHP 8.0 syntax except attributes (when run with PHP 8). The planned 4.x release line will use AST version 80 and require php-ast 1.0.10+ in order to parse/analyze PHP 8.0's #[] attributes

    Bug fixes:

    • Fix false positive PhanUnusedVariable for variable redefined in loop (#4301)
    • Fix handling of -z/--signature-compatibility - that option now enables analyze_signature_compatibility instead of disabling it. (#4303)
    • Fix possible PhanCoalescingNeverUndefined for variable defined in catch block (#4305)
    • Don't emit PhanCompatibleConstructorPropertyPromotion when minimum_target_php_version is 8.0 or newer. (#4307)
    • Infer that PHP 8.0 constructor property promotion's properties have write references. (#4308) They are written to by the constructor.
    • Inherit phpdoc parameter types for the property declaration in php 8.0 constructor property promotion (#4311)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.25 MB)
    phan.phar.asc(593 bytes)
  • 4.0.0-RC1(Dec 13, 2020)

    The Phan v4 release line has the following changes from Phan 3:

    • Bump the minimum required AST version from 70 to 80 (Required to analyze php 8.0 attributes - the rest of the php 8.0 syntax changes are supported in both Phan 3 and Phan 4). A few third party plugins may be affected by the increase of the AST version.
    • Supports analyzing whether #[...] attributes are used properly when run with PHP 8.0+

    Changes

    Merge changes from Phan 3.2.7

    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.26 MB)
    phan.phar.asc(593 bytes)
  • 3.2.7(Dec 13, 2020)

    The Phan 3.x release line uses php-ast's AST version 70 and supports the analysis of all PHP 8.0 syntax except attributes (when run with PHP 8). The planned 4.x release line will use AST version 80 and require php-ast 1.0.10+ in order to parse/analyze PHP 8.0's #[] attributes

    New features (Analysis):

    • Update real parameter names to match php 8.0's parameter names for php's own internal methods (including variadics and those with multiple signatures). (#4263) Update real parameter names, types, and return types for some PECL extensions.
    • Raise the severity of some php 8.0 incompatibility issues to critical.
    • Fix handling of references after renaming variadic reference parameters of fscanf/scanf/mb_convert_variables
    • Mention if PhanUndeclaredFunction is potentially caused by the target php version being too old. (#4230)
    • Improve real type inference for conditionals on literal types (#4288)
    • Change the way the real type set of array access is inferred for mixes of array shapes and arrays (#4296)
    • Emit PhanSuspiciousNamedArgumentVariadicInternal when using named arguments with variadic parameters of internal functions that are not among the few reflection functions known to support named arguments. (#4284)
    • Don't suggest instance properties as alternatives to undefined variables inside of static methods.

    Bug fixes:

    • Support a non-null-mixed type and change the way analysis involving nullability is checked for mixed (phpdoc and real). (#4278, #4276)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.23 MB)
    phan.phar.asc(593 bytes)
  • 4.0.0-alpha5(Nov 27, 2020)

    The Phan v4 release line has the following changes from Phan 3:

    • Bump the minimum required AST version from 70 to 80 (Required to analyze php 8.0 attributes - the rest of the php 8.0 syntax changes are supported in both Phan 3 and Phan 4). A few third party plugins may be affected by the increase of the AST version.
    • Supports analyzing whether #[...] attributes are used properly when run with PHP 8.0+

    Changes

    Merge changes from Phan 3.2.6.

    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.16 MB)
    phan.phar.asc(593 bytes)
  • 3.2.6(Nov 27, 2020)

    The Phan 3.x release line uses php-ast's AST version 70 and supports the analysis of all PHP 8.0 syntax except attributes (when run with PHP 8). The planned 4.x release line will use AST version 80 and require php-ast 1.0.10+ in order to parse/analyze PHP 8.0's #[] attributes

    New features (Analysis):

    • Update many more real parameter names to match php 8.0's parameter names for php's own internal methods. (#4263)
    • Infer that an instance property exists for PHP 8.0 constructor property promotion. (#3938)
    • Infer types of properties from arguments passed into constructor for PHP 8.0 constructor property promotion. (#3938)
    • Emit PhanInvalidNode and PhanRedefineProperty when misusing syntax for constructor property promotion. (#3938)
    • Emit PhanCompatibleConstructorPropertyPromotion when the project's minimum_target_php_version is older than 8.0 (#3938)
    • Emit PhanSuspiciousMagicConstant when using __FUNCTION__ inside of a closure. (#4222)
    Source code(tar.gz)
    Source code(zip)
    phan.phar(10.13 MB)
    phan.phar.asc(593 bytes)
SonarPHP: PHP static analyzer for SonarQube & SonarLint

Code Quality and Security for PHP This SonarSource project is a static code analyser for PHP language used as an extension for the SonarQube platform.

SonarSource 343 Dec 25, 2022
PHPSA - Smart Analyzer for PHP

PHPSA - Smart Analyzer for PHP PHPSA is a development tool aimed at bringing complex analysis for PHP applications and libraries. P.S This software is

Dmitry Patsura 647 Nov 20, 2022
:crystal_ball: Better Reflection is a reflection API that aims to improve and provide more features than PHP's built-in reflection API.

Better Reflection Better Reflection is a reflection API that aims to improve and provide more features than PHP's built-in reflection API. Why is it b

Roave, LLC 1.1k Dec 15, 2022
Beautiful and understandable static analysis tool for PHP

PhpMetrics PhpMetrics provides metrics about PHP project and classes, with beautiful and readable HTML report. Documentation | Twitter | Contributing

PhpMetrics 2.3k Dec 22, 2022
Deptrac is a static code analysis tool for PHP that helps you communicate, visualize and enforce architectural decisions in your projects

Deptrac is a static code analysis tool for PHP that helps you communicate, visualize and enforce architectural decisions in your projects. You can freely define your architectural layers over classes and which rules should apply to them.

QOSSMIC GmbH 2.2k Dec 30, 2022
PHP Static Analysis Tool - discover bugs in your code without running it!

PHPStan - PHP Static Analysis Tool PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even b

PHPStan 11.6k Dec 30, 2022
Performs advanced static analysis on PHP code

PHP Analyzer Please report bugs or feature requests via our website support system ? in bottom right or by emailing [email protected]. Contri

Continuous Inspection 443 Sep 23, 2022
The Exakat Engine : smart static analysis for PHP

Exakat The Exakat Engine is an automated code reviewing engine for PHP. Installation Installation with the phar Phar is the recommended installation p

Exakat 370 Dec 28, 2022
A static php code analysis tool using the Graph Theory

Mondrian Ok guyz, you have a master degree in Graph Theory, you follow Law of Demeter and you live on S.O.L.I.D principles ? Let's have some Fun ! (^ω

Florent Genette 391 Nov 30, 2022
A static analysis tool for finding errors in PHP applications

Psalm Psalm is a static analysis tool for finding errors in PHP applications. Installation To get started, check out the installation guide. Live Demo

Vimeo 5k Jan 2, 2023
Static code analysis to find violations in a dependency graph

PhpDependencyAnalysis PhpDependencyAnalysis is an extendable static code analysis for object-oriented PHP-Projects to generate dependency graphs from

Marco Muths 546 Dec 7, 2022
A static analysis tool for security

progpilot A static analyzer for security purposes Only PHP language is currently supported Installation Option 1: use standalone phar Download the lat

null 271 Dec 27, 2022
Parse: A Static Security Scanner

Parse: A PHP Security Scanner PLEASE NOTE: This tool is still in a very early stage. The work continues... The Parse scanner is a static scanning tool

psec.io 342 Jan 2, 2023
Static Analysis Results Baseliner

Static Analysis Results Baseliner (SARB) Why SARB Requirements Installing Using SARB Examples Further reading Why SARB? If you've tried to introduce a

Dave Liddament 151 Jan 3, 2023
Infection Static Analysis Plugin

Static analysis on top of mutation testing - prevents escaped mutants from being invalid according to static analysis

Roave, LLC 108 Jan 2, 2023
PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD. PHPMD can be seen as an user friendly frontend application for the raw metrics stream measured by PHP Depend.

PHPMD PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD. PHPMD can be seen as an user friendly

PHP Mess Detector 2.1k Jan 8, 2023
Search PHP source code for function & method calls, variables, and more from PHP.

Searching PHP source code made easy Search PHP source code for function & method calls, variable assignments, classes and more directly from PHP. Inst

Permafrost Software 22 Nov 24, 2022
PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.

About PHP_CodeSniffer is a set of two PHP scripts; the main phpcs script that tokenizes PHP, JavaScript and CSS files to detect violations of a define

Squiz Labs 9.9k Jan 4, 2023
A set of tools for lexical and syntactical analysis written in pure PHP.

Welcome to Dissect! master - this branch always contains the last stable version. develop - the unstable development branch. Dissect is a set of tools

Jakub Lédl 221 Nov 29, 2022