-
Notifications
You must be signed in to change notification settings - Fork 198
Support for Php
This document summarizes the PHP language improvements added to Opengrep in 2025.
Here are the PHP features now supported, organized by PHP version:
| Feature | Support | Notes |
|---|---|---|
| PHP 7.1 | ||
| - Union types in catch | ✅ | Note |
| - Class constant visibility | ✅ | Note |
| PHP 7.4 | ||
| - Arrow functions | ✅ | Note |
| PHP 8.0 | ||
| - Union types | ✅ | Note |
| - Match expressions | ✅ | Note |
| - Null coalesce throw | ✅ | Note |
| - Static return type | ✅ | |
| PHP 8.1 | ||
| - Enums | ✅ | Note |
| - First-class callable syntax | ✅ | Note |
| PHP 8.2 | ||
| - Readonly classes | ✅ | Note |
| - DNF types | ✅ | Note |
| PHP 8.3 | ||
| - Dynamic constant fetch | ✅ | Note |
| PHP 8.4 | ||
| - Property hooks | ✅ | Note |
| - Asymmetric visibility | ✅ | Note |
| Infrastructure | ||
| - Thread-safe lexer | ✅ | Note |
| - Interpolated string parsing | ✅ | Note |
The Menhir parser was missing union types. Union types in the tree-sitter parser are translated to tuples, and the Menhir parser now follows the same approach for consistency.
function processInput(int|string $value): int|null {
if (is_string($value)) {
return strlen($value);
}
return $value > 0 ? $value : null;
}Added PHP 7.4 arrow function syntax to the Menhir parser. PHP arrow functions (fn($x) => $x + 1) are syntactically different from Facebook's HHVM extension syntax ($x ==> $x + 1), but both are represented the same way in the AST.
$fn = fn($x) => $x + 1;
// Equivalent to:
$fn = function($x) {
return $x + 1;
};Fixed a bug in the tree-sitter parser where interpolated strings were incorrectly parsed as literal strings. For example:
"convert $filename"was being parsed literally as a string instead of recognizing $filename as an interpolated variable.
The Menhir parser was missing the ?? token for PHP 8.0's null coalesce operator. Additionally, throw was modified to be parsed as an expression so it can be used with ??.
return shell_exec($command)
?? throw new RuntimeException('Failed to execute command');Added PHP 8.0 match expressions to the Menhir parser. Also fixed an issue in switch (and match) that prevented ellipses in the body. The following patterns are now valid:
switch($F) {
...
}
match ($F) {
...
}Added PHP 8.1 enum definitions including backed enums:
enum Status: string {
case Active = 'active';
case Pending = 'pending';
case Inactive = 'inactive';
}PHP 7.1 multi-catch syntax allowing multiple exception types in a single catch block:
try {
riskyOperation();
} catch (InvalidArgumentException | TypeError | ValueError $e) {
handleError($e);
}PHP 7.1 visibility modifiers for class constants:
class Config {
public const PUBLIC_CONST = 1;
protected const PROTECTED_CONST = 2;
private const PRIVATE_CONST = 3;
}PHP 8.1 first-class callable syntax creates closures from callables:
$fn = strlen(...); // Closure::fromCallable('strlen')
$fn = $obj->method(...); // Closure::fromCallable([$obj, 'method'])
$fn = Foo::bar(...); // Closure::fromCallable([Foo::class, 'bar'])In Opengrep patterns, ... retains its ellipsis meaning for pattern matching. In particular in order to wrote a pattern that matches a "callable ..." you need to use Closure::fromCallable
PHP 8.2 readonly classes where all properties are implicitly readonly:
readonly class ImmutablePoint {
public int $x;
public int $y;
}PHP 8.2 Disjunctive Normal Form types combine union and intersection types:
function process((Countable&Iterator)|null $input): (A&B)|C {
// ...
}PHP 8.3 dynamic class constant fetch allows accessing constants using variable names:
$name = 'VERSION';
echo Config::{$name};PHP 8.4 property hooks allow defining custom get/set behavior directly on properties:
class User {
// Block syntax
public string $name {
get { return $this->name; }
set { $this->name = strtoupper($value); }
}
// Arrow syntax
public int $age {
get => $this->age;
set => max(0, $value);
}
}PHP 8.4 asymmetric visibility allows different visibility for reading and writing properties:
class Counter {
public private(set) int $count = 0; // Public read, private write
public protected(set) string $name = ""; // Public read, protected write
}The PHP primary parser lexer was made thread-safe as part of the transition from parmap to domainslib. This enables parallel file processing without race conditions and improves performance on multi-core systems.