3v4l.org

run code in 300+ PHP versions simultaneously
<?php $f = function(int $i) { var_dump($i); }; // Some::new() // Some::match() final class Mangling { private $mangle = []; public function __construct(...$args) { foreach ($args as $arg) { if ($arg !== null) { if (is_callable($arg)) { $this->mangle[] = serialize($arg); } else { $this->mangle[] = (string) $arg; } } else { $this->mangle[] = '_'; } } } public static function new(...$args): self { return new self(...$args); } public function implode(string $glue): string { return implode($glue, $this->mangle); } } const _ = null; interface MatchingInterface { public function matches(array $cases): void; } interface DestructureInterface { public function destruct(): array; } trait MatchingTrait { private $mangling; private $values = []; public function __construct(...$values) { $this->mangling = new Mangling(...$values); $this->values = $values; } public static function new(...$values): self { return new self($values); } private static function into(Mangling $mangling): string { return sprintf('%s(%s)', static::class, $mangling->implode(',')); } public static function match(...$values): string { return self::into(new Mangling(...$values)); } private static function unserialize(string $s) { return @unserialize($s); } private function getPatternMatchWith(array $pattern): array { $cp = count($pattern); $mangle = []; $params = []; foreach ($this->values as $index => $value) { if ($index >= $cp) { $params[] = $value; continue; } if (array_key_exists($index, $pattern) && $pattern[$index] !== _) { $pat = $pattern[$index]; if ($pat !== _) { $closure = self::unserialize($pat); if (is_callable($closure) && !$closure($value)) { return ['mangle' => _, 'params' => []]; } } $params[] = $value; $mangle[] = $value; } else { $mangle[] = _; } } return ['mangle' => self::into(new Mangling(...$mangle)), 'params' => $params]; } private static function intoPattern(string $mangling): array { $pattern = sprintf('/%s\((.+)\)/i', static::class); if (preg_match($pattern, $mangling, $matches)) { return array_map(function(string $param) { return trim($param) === '_' ? _ : $param; }, preg_split('/,\s*/', $matches[1])); } return []; } private function intoMangling(array $pattern): string { $output = []; foreach ($pattern as $index => $value) { if ($value !== _ && self::unserialize($value) !== false) { $output[] = $this->values[$index]; } else { $output[] = $value; } } return self::into(new Mangling(...$output)); } public function matches(array $cases): void { foreach ($cases as $mangling => $closure) { $pattern = self::intoPattern($mangling); ['mangle' => $mangle, 'params' => $params] = $this->getPatternMatchWith($pattern); if ($this->intoMangling($pattern) === $mangle) { $closure(...$params); break; } } } public function toString(): string { return sprintf('%s(%s)', static::class, $this->mangling->implode(',')); } public function __toString(): string { return $this->toString(); } } trait DestructureTrait { public function destruct(): array { return $this->values; } } interface ADTInterface extends MatchingInterface, DestructureInterface { } trait ADTTrait { use MatchingTrait; use DestructureTrait; } final class TypeClosure { private $name; private $typecheck; private $value; public function __construct(string $name, callable $typecheck, &$value) { $this->name = $name; $this->typecheck = $typecheck; $this->value = &$value; } public function __invoke($param): bool { $this->value = ($this->typecheck)($param) ? $param : _; return $this->value !== _; } } function typeof(string $name, callable $typecheck, &$value): TypeClosure { return new TypeClosure($name, $typecheck, $value); } function int(&$value = null): TypeClosure { return typeof('int', 'is_int', $value); } function any(&$value = null): TypeClosure { return typeof('any', function() { return true; }, $value); } function string(&$value = null): TypeClosure { return typeof('string', 'is_string', $value); } final class LetBinding { private $destructure; public function __construct(DestructureInterface $destructure) { $this->destructure = $destructure; } public function be(...$closures): bool { $params = $this->destructure->destruct(); foreach ($closures as $index => $closure) { if (array_key_exists($index, $params) && is_callable($closure)) { $param = $params[$index]; if (!$closure($param)) { return false; } } } return true; } } function let(DestructureInterface $destructure): LetBinding { return new LetBinding($destructure); } interface Option { } final class Some implements Option, ADTInterface { use ADTTrait; } $opt = new Some(42, 23); print '#1: '; $opt->matches([Some::match(_, 23) => $f]); print '#2: '; $opt->matches([Some::match(_) => $f]); print '#3: '; if (let($opt)->be(int($x), int($y))) { var_dump($x); var_dump($y); } print '#4: '; if (let($opt)->be(_, int($y))) { var_dump($y); } interface Gender { } final class Male implements Gender, ADTInterface { use ADTTrait; } final class Female implements Gender, ADTInterface { use ADTTrait; } final class Other implements Gender, ADTInterface { use ADTTrait; } function gender1(Gender $gender): void { print '#5: '; $gender->matches([Male::match(string($name), _) => function(string $name) { var_dump($name); }]); } function gender2(Gender $gender): void { print '#5: '; $gender->matches([Male::match(_) => function(string $name) { var_dump($name); }]); } $gender = new Male('Hans', 'Franz'); gender1($gender); gender2($gender);

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
8.3.60.0090.00918.80
8.3.50.0040.01218.40
8.3.40.0100.01019.35
8.3.30.0120.00319.21
8.3.20.0060.00319.33
8.3.10.0050.00322.07
8.3.00.0090.00020.71
8.2.180.0110.01118.71
8.2.170.0160.00322.96
8.2.160.0090.00620.99
8.2.150.0050.00324.18
8.2.140.0060.00324.66
8.2.130.0060.00320.07
8.2.120.0060.00326.35
8.2.110.0170.00721.06
8.2.100.0040.01118.16
8.2.90.0060.00318.00
8.2.80.0090.00017.97
8.2.70.0030.00618.18
8.2.60.0000.00818.41
8.2.50.0080.00018.10
8.2.40.0040.00419.45
8.2.30.0050.00319.30
8.2.20.0050.00318.14
8.2.10.0040.00418.13
8.2.00.0090.00017.98
8.1.280.0060.01325.92
8.1.270.0040.00719.08
8.1.260.0000.00826.35
8.1.250.0080.00028.09
8.1.240.0090.00022.63
8.1.230.0070.00422.30
8.1.220.0000.00917.91
8.1.210.0030.00618.77
8.1.200.0030.00717.63
8.1.190.0070.00417.60
8.1.180.0090.00018.10
8.1.170.0030.00518.60
8.1.160.0000.00919.13
8.1.150.0000.00819.10
8.1.140.0040.00422.34
8.1.130.0030.00617.67
8.1.120.0000.00817.75
8.1.110.0000.00817.73
8.1.100.0000.00917.75
8.1.90.0000.00817.69
8.1.80.0040.00417.69
8.1.70.0040.00417.57
8.1.60.0040.00417.75
8.1.50.0040.00717.60
8.1.40.0050.00317.71
8.1.30.0030.00517.81
8.1.20.0030.00517.92
8.1.10.0080.00017.71
8.1.00.0040.00417.63
8.0.300.0000.00818.90
8.0.290.0030.00517.00
8.0.280.0050.00318.61
8.0.270.0050.00217.31
8.0.260.0000.00717.18
8.0.250.0030.00617.25
8.0.240.0070.00017.18
8.0.230.0030.00617.28
8.0.220.0080.00017.25
8.0.210.0050.00217.22
8.0.200.0000.00717.26
8.0.190.0040.00417.22
8.0.180.0050.00317.28
8.0.170.0060.00317.16
8.0.160.0030.00617.21
8.0.150.0060.00317.14
8.0.140.0000.00817.14
8.0.130.0040.00413.69
8.0.120.0060.00317.21
8.0.110.0030.00717.22
8.0.100.0040.00417.02
8.0.90.0080.00017.21
8.0.80.0110.00917.17
8.0.70.0050.00317.20
8.0.60.0000.00817.18
8.0.50.0050.00317.27
8.0.30.0100.01017.40
8.0.20.0100.01017.53
8.0.10.0040.00417.45
8.0.00.0130.00916.97
7.4.330.0060.00015.55
7.4.320.0070.00016.85
7.4.300.0070.00016.90
7.4.290.0000.00716.86
7.4.280.0000.01016.83
7.4.270.0040.00416.94
7.4.260.0040.00416.81
7.4.250.0040.00416.82
7.4.240.0030.00516.95
7.4.230.0020.00516.69
7.4.220.0090.00017.04
7.4.210.0100.00816.87
7.4.200.0000.00716.95
7.4.160.0100.00816.94
7.4.140.0100.01017.86
7.4.130.0160.00316.83
7.4.120.0110.00816.89
7.4.110.0170.00716.80
7.4.100.0160.00316.88
7.4.90.0110.00716.66
7.4.80.0080.01319.39
7.4.70.0130.00616.92
7.4.60.0120.00616.80
7.4.50.0100.00716.93
7.4.40.0090.00916.93
7.3.330.0030.00313.67
7.3.320.0000.00613.57
7.3.310.0090.00016.60
7.3.300.0040.00416.73
7.3.290.0000.00716.68
7.3.280.0060.01616.65
7.3.260.0130.00916.81
7.3.240.0070.01116.83
7.3.230.0060.01116.78
7.3.210.0090.01217.03
7.3.200.0170.00016.94
7.3.190.0120.01217.03
7.3.180.0070.01016.78
7.3.170.0110.01416.80
7.3.160.0130.00316.97
7.2.330.0110.00817.05
7.2.320.0100.01016.99
7.2.310.0080.01117.07
7.2.300.0090.00917.13
7.2.290.0070.01116.98

preferences:
58.46 ms | 401 KiB | 5 Q