Skip to content

Instantly share code, notes, and snippets.

@jerguslejko
Last active February 14, 2019 16:36
Show Gist options
  • Select an option

  • Save jerguslejko/3873a48d1a790e1f7385fc6ebc486fa1 to your computer and use it in GitHub Desktop.

Select an option

Save jerguslejko/3873a48d1a790e1f7385fc6ebc486fa1 to your computer and use it in GitHub Desktop.

"Safe PHP" research

PHP type checker which uses native and phpDocumentor (extended) types. When types are present, the code is still valid PHP.

Usage

$ safe-php script.php

How does it work:

  • uses php -l to ensure correct syntax
  • parses the source file, analyzes it and reports the results
  • if successfull then proxy to php else display errors/warnings

Types

  1. use native PHP types for simple cases

    function foo(string $x): int
    {
        ...
    }
  2. for unsupported types, use phpDocumentor

    /**
     * @param string[] $xs
     *
     * @return int|\DateTime
     */
    function foo($xs)
    {
        ...
    }

    Native and phpDoc types should be sync as much as possible (array and string[]), phpDoc types take precedence.

  3. (?) for types which are not supported by phpDocumentor, extend the phpDocumentor syntax

    /**
     * @return [int, string] Pseudo tuple type
     */
    function foo()
    {
        ...
    }
  4. generic functions using extended phpDocumentor syntax

    /**
     * @param A $x
     * @return A[]
     */
    function foo($x): array
    {
        ...
    }
  5. (?) for existing functions/classes in third-party pkgs, allow to create separate definitions

    /**
     * @typedef function foo($x): int
     *
     * @param string[] $x
     * @return int
     */

    Assume "ANY" type for untyped code. (How much untyped do we allow? It's useful when using third-party libraries.)

  6. type inference for variables

    $name = "Jergus"; // $name :: string
    
    /** @var string[] */
    $xs = unknownSource();
  7. guard clauses change (union) types

    $x = fn(); // $x :: string | int
    
    if (is_integer($x)) {
        $x; // $x :: int
    } else {
        $x; // $x :: string
    }

Implementation

  1. using parser combinators to produce a parser for valid PHP code
  2. write difference evals to validate/infer/inspect types (?)

Potential additions

  1. eliminate dead branches
  2. spot duplicates?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment