xref: /PHP-Parser/lib/PhpParser/PhpVersion.php (revision caf54044)
1<?php declare(strict_types=1);
2
3namespace PhpParser;
4
5/**
6 * A PHP version, representing only the major and minor version components.
7 */
8class PhpVersion {
9    /** @var int Version ID in PHP_VERSION_ID format */
10    public int $id;
11
12    /** @var int[] Minimum versions for builtin types */
13    private const BUILTIN_TYPE_VERSIONS = [
14        'array'    => 50100,
15        'callable' => 50400,
16        'bool'     => 70000,
17        'int'      => 70000,
18        'float'    => 70000,
19        'string'   => 70000,
20        'iterable' => 70100,
21        'void'     => 70100,
22        'object'   => 70200,
23        'null'     => 80000,
24        'false'    => 80000,
25        'mixed'    => 80000,
26        'never'    => 80100,
27        'true'     => 80200,
28    ];
29
30    private function __construct(int $id) {
31        $this->id = $id;
32    }
33
34    /**
35     * Create a PhpVersion object from major and minor version components.
36     */
37    public static function fromComponents(int $major, int $minor): self {
38        return new self($major * 10000 + $minor * 100);
39    }
40
41    /**
42     * Get the newest PHP version supported by this library. Support for this version may be partial,
43     * if it is still under development.
44     */
45    public static function getNewestSupported(): self {
46        return self::fromComponents(8, 4);
47    }
48
49    /**
50     * Get the host PHP version, that is the PHP version we're currently running on.
51     */
52    public static function getHostVersion(): self {
53        return self::fromComponents(\PHP_MAJOR_VERSION, \PHP_MINOR_VERSION);
54    }
55
56    /**
57     * Parse the version from a string like "8.1".
58     */
59    public static function fromString(string $version): self {
60        if (!preg_match('/^(\d+)\.(\d+)/', $version, $matches)) {
61            throw new \LogicException("Invalid PHP version \"$version\"");
62        }
63        return self::fromComponents((int) $matches[1], (int) $matches[2]);
64    }
65
66    /**
67     * Check whether two versions are the same.
68     */
69    public function equals(PhpVersion $other): bool {
70        return $this->id === $other->id;
71    }
72
73    /**
74     * Check whether this version is greater than or equal to the argument.
75     */
76    public function newerOrEqual(PhpVersion $other): bool {
77        return $this->id >= $other->id;
78    }
79
80    /**
81     * Check whether this version is older than the argument.
82     */
83    public function older(PhpVersion $other): bool {
84        return $this->id < $other->id;
85    }
86
87    /**
88     * Check whether this is the host PHP version.
89     */
90    public function isHostVersion(): bool {
91        return $this->equals(self::getHostVersion());
92    }
93
94    /**
95     * Check whether this PHP version supports the given builtin type. Type name must be lowercase.
96     */
97    public function supportsBuiltinType(string $type): bool {
98        $minVersion = self::BUILTIN_TYPE_VERSIONS[$type] ?? null;
99        return $minVersion !== null && $this->id >= $minVersion;
100    }
101
102    /**
103     * Whether this version supports [] array literals.
104     */
105    public function supportsShortArraySyntax(): bool {
106        return $this->id >= 50400;
107    }
108
109    /**
110     * Whether this version supports [] for destructuring.
111     */
112    public function supportsShortArrayDestructuring(): bool {
113        return $this->id >= 70100;
114    }
115
116    /**
117     * Whether this version supports flexible heredoc/nowdoc.
118     */
119    public function supportsFlexibleHeredoc(): bool {
120        return $this->id >= 70300;
121    }
122
123    /**
124     * Whether this version supports trailing commas in parameter lists.
125     */
126    public function supportsTrailingCommaInParamList(): bool {
127        return $this->id >= 80000;
128    }
129
130    /**
131     * Whether this version allows "$var =& new Obj".
132     */
133    public function allowsAssignNewByReference(): bool {
134        return $this->id < 70000;
135    }
136
137    /**
138     * Whether this version allows invalid octals like "08".
139     */
140    public function allowsInvalidOctals(): bool {
141        return $this->id < 70000;
142    }
143
144    /**
145     * Whether this version allows DEL (\x7f) to occur in identifiers.
146     */
147    public function allowsDelInIdentifiers(): bool {
148        return $this->id < 70100;
149    }
150
151    /**
152     * Whether this version supports yield in expression context without parentheses.
153     */
154    public function supportsYieldWithoutParentheses(): bool {
155        return $this->id >= 70000;
156    }
157
158    /**
159     * Whether this version supports unicode escape sequences in strings.
160     */
161    public function supportsUnicodeEscapes(): bool {
162        return $this->id >= 70000;
163    }
164}
165