3v4l.org

run code in 300+ PHP versions simultaneously
<?php interface ILexer { /** * return associative array containing tokens for parser * @param string $input code to tokenize * @return array */ public function tokenize($input); } interface INameValidator { /** * Checks if name is valid. In a case of failure trigger syntax error. * @param string $name * @return void */ public function validate($name); } interface IParser { /** * Sets array of keywords. * @param array $keywords associative array where key is keyword and value respective php instruction. * @return void */ public function setKeywords(array $keywords); /** * Parses code. Checks for syntax errors. * If no error occurs returns data for compiler to assemble php class * otherwise trigger syntax error. * @param string $input code to parse. * @return array IParserResult */ public function parse($input); } interface IParseResult { public function getDefinition(); public function getName(); public function getConstants(); } interface ICompiler { /** * Compiles enum into valid php class * @param string $input code to compile. * @return string */ public function compile($input); } interface IErrorManager { /** * Triggers fatal error. * @param string $message error message * @return void */ public function ariseFatal($message); /** * Triggers warning. * @param string $message error message * @return void */ public function ariseWarning($message); /** * Triggers notice. * @param string $message error message * @return void */ public function ariseNotice($message); } //I know this lexer sucks. class Lexer extends CompilerElement implements ILexer { // Potential hidden dependency private $specialChars = array( '{' => 'start_body', '}' => 'end_body' ); public function tokenize($input) { if (!is_string($input)) { $this->getErrorManager()->ariseFatal(get_class($this).'::parse expects parameter 1 to be string. '.gettype($input).' given.'); } $tokens = array(); $token = $this->getEmptyToken(); $tokenMetadata = $this->getDefaultTokenMetadata(); $inputLength = strlen($input); for ($i = 0; $i < $inputLength; $i++) { $current = $input[$i]; //check if special character if (isset($this->specialChars[$current])) { $token[$this->specialChars[$current]] = $current; if ($i !== $inputLength - 1) continue; } if (isset($token['end_body'])) { $tokens[] = $token; $token = $this->getEmptyToken(); $tokenMetadata = $this->getDefaultTokenMetadata(); if ($i === $inputLength - 1) continue; } $isWhitespace = ctype_space($current); if (isset($token['start_body'])) { //skip if whitespace if ($isWhitespace) { continue; } if ($current === ',') { $tokenMetadata['newItem'] = true; $tokenMetadata['newItemNameResolved'] = false; continue; } if ($current === '=') { $tokenMetadata['newItemNameResolved'] = true; continue; } if ($tokenMetadata['newItem']) { $token['e_'.$current] = null; $tokenMetadata['newItem'] = false; } else { end($token); $lastKey = key($token); if (!$tokenMetadata['newItemNameResolved']) { unset($token[$lastKey]); $token[$lastKey.$current] = null; } else { $token[$lastKey] .= $current; } } continue; } if (!$tokenMetadata['typeResolved']) { if ($isWhitespace) { if (strlen($token['type']) === 0) { continue; } else { $tokenMetadata['typeResolved'] = true; } } else { $token['type'] .= $current; } } else if (!$tokenMetadata['nameResolved']) { if ($isWhitespace) { if (strlen($token['name']) === 0) { continue; } else { $tokenMetadata['nameResolved'] = true; } } else { $token['name'] .= $current; } } } return $tokens; } private function getEmptyToken() { return array( 'type' => '', 'name' => '' ); } private function getDefaultTokenMetadata() { return array( 'typeResolved' => false, 'nameResolved' => false, 'newItem' => true, 'newItemNameResolved' => false ); } public function __construct(IErrorManager $errorManager) { parent::__construct($errorManager); } } class NameValidator extends CompilerElement implements INameValidator { private $allowedChars; public function validate($name) { if (!is_string($name)) { $this->getErrorManager()->ariseFatal(get_class($this).'::validate expects parameter 1 to be string. '.gettype($name).' given.'); } $nameLength = strlen($name); for ($i = 0; $i < $nameLength; $i++) { $current = $name[$i]; if ($i === 0 && !ctype_alpha($current)) { $this->getErrorManager()->ariseFatal('Name should start with alphabetic characters. Given name '.$name.' starts with: '.$current); } if (!in_array(strtolower($current), $this->allowedChars, true)) { $this->getErrorManager()->ariseFatal('Unexpected character '.$current.' in name '.$name.'.'); } } } public function __construct(IErrorManager $errorManager) { parent::__construct($errorManager); // Yes, I hate that everything is allowed as name in php. $this->allowedChars = str_split('abcdefghijklmnopqrstuvwxyz0123456789'); } } class Parser extends CompilerElement implements IParser { private $lexer; private $nameValidator; private $keywords = array(); public function setKeywords(array $keywords) { $this->keywords = $keywords; } public function parse($input) { if (!is_string($input)) { $this->getErrorManager()->ariseFatal(get_class($this).'::parse expects parameter 1 to be string. '.gettype($input).' given.'); } $input = $this->cleanUp($input); $errorManager = $this->getErrorManager(); $allTokens = $this->lexer->tokenize($input); $result = array(); $currentResult = null; $processingBody = false; foreach ($allTokens as $tokens) { foreach ($tokens as $token => $tokenValue) { switch ($token) { case 'type': if ($currentResult !== null || !isset($this->keywords[$tokenValue])) { $errorManager->ariseFatal('Syntax error. Unexpected '.$tokenValue); } $currentResult = new ParseResult($this->keywords[$tokenValue], $errorManager); break; case 'name': if ($currentResult === null) { $errorManager->ariseFatal('Syntax error. Unexpected '.$tokenValue); } $this->nameValidator->validate($tokenValue); $currentResult->setName($tokenValue); break; case 'start_body': if ($currentResult === null || $currentResult->getName() === null) { $errorManager->ariseFatal('Syntax error. Unexpected '.$tokenValue); } $processingBody = true; break; case 'end_body': if ($currentResult === null || $currentResult->getName() === null || $processingBody === false) { $errorManager->ariseFatal('Syntax error. Unexpected '.$tokenValue); } $result[] = $currentResult; $currentResult = null; $processingBody = false; break; default: if ($processingBody === true && $currentResult !== null) { $name = ltrim($token, 'e_'); $this->nameValidator->validate($name); if ($tokenValue === null) { $constants = $currentResult->getConstants(); $last = end($constants); $value = ($last !== false) ? $last + 1 : 0; } else { $value = $tokenValue; } $currentResult->setItem($name, $value); } else { $errorManager->ariseFatal('Syntax error. Unexpected '.$tokenValue); } break; } } } return $result; } private function cleanUp($input) { return trim($input); } public function __construct(ILexer $lexer, INameValidator $nameValidator, IErrorManager $errorManager) { parent::__construct($errorManager); $this->lexer = $lexer; $this->nameValidator = $nameValidator; } } class ParseResult extends CompilerElement implements IParseResult { private $definition; private $name; private $constants = array(); public function getDefinition() { return $this->definition; } public function getName() { return $this->name; } public function getConstants() { return $this->constants; } public function setItem($name, $value) { if (!is_string($name)) { $this->getErrorManager()->ariseFatal('Enumeration item name can only be string.'); } if (!is_numeric($value)) { $this->getErrorManager()->ariseFatal('Enumeration item can only hold numeric value.'); } $this->constants[$name] = (ctype_digit($value) === true) ? (int)$value : (double)$value; } public function setName($name) { if (!is_string($name)) { $this->getErrorManager()->ariseFatal(get_class($this).'::setName expects parameter 1 to be string. '.gettype($name).' given.'); } $this->name = $name; } public function __construct($definition, IErrorManager $errorManager) { parent::__construct($errorManager); if (!is_string($definition)) { $this->getErrorManager()->ariseFatal(get_class($this).'::__construct expects parameter 1 to be string. '.gettype($definition).' given.'); } $this->definition = $definition; } } abstract class CompilerElement { private $errorManager; protected function getErrorManager() { return $this->errorManager; } protected function __construct(IErrorManager $errorManager) { $this->errorManager = $errorManager; } } class Enum2PhpCompiler implements ICompiler { const INDENTATION_CHAR = "\t"; private $parser; public function compile($input) { $parseResult = $this->parser->parse($input); $return = ''; foreach ($parseResult as $result) { $return .= $this->generateClass($result); } return $return; } private function generateClass(IParseResult $parseResult) { $return = $parseResult->getDefinition().' '.$parseResult->getName().' {'.PHP_EOL; foreach ($parseResult->getConstants() as $name => $value) { $return .= Enum2PhpCompiler::INDENTATION_CHAR.'const '.$name.' = '.$value.';'.PHP_EOL; } $return .= Enum2PhpCompiler::INDENTATION_CHAR.'private function __construct() {}'.PHP_EOL; $return .= '}'.PHP_EOL; return $return; } public function __construct(IParser $parser) { $this->parser = $parser; $this->parser->setKeywords(array('enum' => 'final class')); } } class ErrorManager implements IErrorManager { public function ariseFatal($message) { $this->triggerError($message, E_USER_ERROR); } public function ariseWarning($message) { $this->triggerError($message, E_USER_WARNING); } public function ariseNotice($message) { $this->triggerError($message, E_USER_NOTICE); } private function triggerError($message, $type) { trigger_error((string)$message, (int)$type); } } $errorManager = ErrorManager(); $nameValidator = NameValidator($errorManager); $lexer = new Lexer($errorManager); $parser = new Parser($lexer, $nameValidator, $errorManager); $compiler = new Enum2PhpCompiler($parser); $enum = <<<PHP enum MyEnum { Item1 = 1, Item2 = 5, Item3 } enum AnotherEnum { Item } PHP; eval($compiler->compile($enum)); var_dump(MyEnum::Item1, MyEnum::Item2, MyEnum::Item3, AnotherEnum::Item);

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.00916.63
8.3.50.0090.00921.92
8.3.40.0120.00318.92
8.3.30.0170.00319.20
8.3.20.0040.00420.34
8.3.10.0000.00823.48
8.3.00.0080.00020.84
8.2.180.0100.01016.63
8.2.170.0070.01122.96
8.2.160.0070.01320.37
8.2.150.0030.00524.18
8.2.140.0000.00824.66
8.2.130.0090.00926.16
8.2.120.0040.00422.08
8.2.110.0070.00322.30
8.2.100.0040.00818.03
8.2.90.0030.00519.17
8.2.80.0050.00318.05
8.2.70.0040.00817.63
8.2.60.0060.00318.05
8.2.50.0030.00618.07
8.2.40.0040.00418.34
8.2.30.0040.00418.09
8.2.20.0040.00417.92
8.2.10.0050.00317.77
8.2.00.0000.00817.77
8.1.280.0220.00025.92
8.1.270.0090.00023.76
8.1.260.0040.00426.35
8.1.250.0000.00928.09
8.1.240.0060.00323.66
8.1.230.0070.00719.20
8.1.220.0050.00317.79
8.1.210.0050.00318.77
8.1.200.0070.00317.35
8.1.190.0030.00617.66
8.1.180.0040.00418.10
8.1.170.0030.00718.77
8.1.160.0050.00222.16
8.1.150.0080.00018.60
8.1.140.0040.00417.48
8.1.130.0000.00717.92
8.1.120.0000.00717.52
8.1.110.0030.00517.48
8.1.100.0000.00817.55
8.1.90.0080.00317.52
8.1.80.0000.00817.51
8.1.70.0000.00717.52
8.1.60.0090.00017.58
8.1.50.0000.00917.57
8.1.40.0000.00917.62
8.1.30.0080.00017.67
8.1.20.0030.00517.67
8.1.10.0040.00417.65
8.1.00.0030.00617.49
8.0.300.0080.00018.77
8.0.290.0090.00017.05
8.0.280.0040.00418.60
8.0.270.0070.00017.30
8.0.260.0030.00317.03
8.0.250.0070.00017.21
8.0.240.0040.00417.13
8.0.230.0000.00717.17
8.0.220.0040.00417.09
8.0.210.0000.00717.15
8.0.200.0030.00517.19
8.0.190.0090.00017.10
8.0.180.0040.00417.16
8.0.170.0030.00517.21
8.0.160.0030.00517.07
8.0.150.0040.00716.95
8.0.140.0030.00616.96
8.0.130.0000.00913.61
8.0.120.0040.00416.99
8.0.110.0040.00417.00
8.0.100.0080.00017.05
8.0.90.0040.00417.14
8.0.80.0150.00517.05
8.0.70.0000.00817.09
8.0.60.0050.00316.96
8.0.50.0000.00817.00
8.0.30.0080.01117.38
8.0.20.0100.00917.40
8.0.10.0000.00817.22
8.0.00.0090.01016.84
7.4.330.0050.00015.00
7.4.320.0000.00716.63
7.4.300.0040.00416.68
7.4.290.0070.00016.50
7.4.280.0000.00816.60
7.4.270.0000.00716.53
7.4.260.0040.00416.48
7.4.250.0040.00416.46
7.4.240.0040.00416.57
7.4.230.0040.00416.71
7.4.220.0100.01016.54
7.4.210.0030.01216.71
7.4.200.0080.00016.71
7.4.190.0030.00516.55
7.4.160.0090.00916.52
7.4.150.0200.00017.40
7.4.140.0050.01217.86
7.4.130.0090.01116.66
7.4.120.0080.01316.51
7.4.110.0120.00916.77
7.4.100.0110.00716.66
7.4.90.0190.00316.63
7.4.80.0160.00819.39
7.4.70.0100.00716.63
7.4.60.0110.00716.51
7.4.50.0000.00516.59
7.4.40.0030.00922.77
7.4.30.0100.00716.64
7.4.00.0170.00015.35
7.3.330.0000.00613.24
7.3.320.0030.00313.31
7.3.310.0040.00416.35
7.3.300.0030.00516.34
7.3.290.0090.00616.42
7.3.280.0080.01216.48
7.3.270.0110.00717.40
7.3.260.0120.01216.54
7.3.250.0090.00916.54
7.3.240.0100.01016.75
7.3.230.0100.00716.67
7.3.210.0090.01716.43
7.3.200.0150.00419.39
7.3.190.0120.01216.59
7.3.180.0060.01016.63
7.3.170.0110.00616.57
7.3.160.0100.00716.54
7.3.120.0070.00714.82
7.3.10.0100.00716.69
7.3.00.0060.00816.69
7.2.330.0030.01516.60
7.2.320.0110.00616.82
7.2.310.0100.01316.60
7.2.300.0140.00716.73
7.2.290.0100.00716.59
7.2.130.0000.01016.57
7.2.120.0070.01016.83
7.2.110.0000.01416.89
7.2.100.0040.00716.52
7.2.90.0080.00416.98
7.2.80.0000.01416.70
7.2.70.0080.00416.71
7.2.60.0060.00916.83
7.2.50.0060.00916.73
7.2.40.0030.01316.84
7.2.30.0090.00316.87
7.2.20.0040.01116.47
7.2.10.0000.01516.59
7.2.00.0070.00717.78
7.1.250.0030.00715.51
7.1.200.0000.01315.50
7.1.100.0070.00318.22
7.1.70.0110.00016.84
7.1.60.0100.01419.29
7.1.50.0070.01116.88
7.1.00.0030.07722.45
7.0.200.0060.00916.43
7.0.140.0030.07722.09
7.0.100.0030.07719.98
7.0.90.0070.07720.22
7.0.80.0070.08020.10
7.0.70.0130.08319.98
7.0.60.0270.07320.01
7.0.50.0100.07720.21
7.0.40.0100.06719.91
7.0.30.0130.08020.08
7.0.20.0170.04320.07
7.0.10.0100.07020.18
7.0.00.0100.07720.03
5.6.280.0100.07020.97
5.6.250.0030.07720.88
5.6.240.0070.03720.74
5.6.230.0030.06320.63
5.6.220.0030.08020.55
5.6.210.0100.08320.63
5.6.200.0170.07321.17
5.6.190.0100.05721.09
5.6.180.0100.08021.00
5.6.170.0130.07721.19
5.6.160.0170.07021.20
5.6.150.0100.08321.02
5.6.140.0130.07321.16
5.6.130.0070.08721.09
5.6.120.0130.08021.13
5.6.110.0130.08321.02
5.6.100.0100.08021.14
5.6.90.0070.07321.11
5.6.80.0070.06020.50
5.6.70.0000.04720.46
5.6.60.0000.09320.46
5.6.50.0170.06320.53
5.6.40.0100.08320.38
5.6.30.0130.06320.46
5.6.20.0070.08020.45
5.6.10.0200.06720.45
5.6.00.0200.06720.54
5.5.380.0170.07020.41
5.5.370.0100.08320.47
5.5.360.0030.08320.46
5.5.350.0100.06020.41
5.5.340.0100.08320.93
5.5.330.0070.08020.89
5.5.320.0170.07320.84
5.5.310.0070.08320.84
5.5.300.0100.07720.86
5.5.290.0030.09320.89
5.5.280.0100.08720.93
5.5.270.0100.08720.81
5.5.260.0100.07320.91
5.5.250.0100.04720.77
5.5.240.0070.05720.32
5.5.230.0100.08020.07
5.5.220.0070.08320.19
5.5.210.0130.07320.25
5.5.200.0170.06020.30
5.5.190.0070.08020.30
5.5.180.0100.07720.25
5.5.160.0130.07720.21
5.5.150.0030.07720.33
5.5.140.0070.07720.27
5.5.130.0070.07320.21
5.5.120.0100.07020.29
5.5.110.0030.04020.24
5.5.100.0000.08320.23
5.5.90.0130.06020.13
5.5.80.0100.05020.10
5.5.70.0030.08320.12
5.5.60.0200.05320.21
5.5.50.0070.07720.14
5.5.40.0130.07020.11
5.5.30.0130.07020.07
5.5.20.0070.06720.16
5.5.10.0000.05320.02
5.5.00.0130.04720.10
5.4.450.0100.07719.56
5.4.440.0170.07719.39
5.4.430.0100.07319.39
5.4.420.0070.08019.48
5.4.410.0200.06319.45
5.4.400.0070.06319.17
5.4.390.0100.07018.90
5.4.380.0130.05019.08
5.4.370.0070.07718.90
5.4.360.0130.06718.93
5.4.350.0070.08319.04
5.4.340.0030.08719.09
5.4.320.0130.04019.08
5.4.310.0130.07018.93
5.4.300.0070.07718.93
5.4.290.0030.07019.08
5.4.280.0070.04019.09
5.4.270.0030.07019.22
5.4.260.0000.06018.99
5.4.250.0100.05019.15
5.4.240.0130.05319.09
5.4.230.0100.07019.21
5.4.220.0070.07719.07
5.4.210.0030.08319.04
5.4.200.0130.06719.22
5.4.190.0030.07719.10
5.4.180.0170.06719.06
5.4.170.0130.06719.22
5.4.160.0130.07018.92
5.4.150.0070.08019.14
5.4.140.0070.07716.45
5.4.130.0100.07316.48
5.4.120.0030.07316.34
5.4.110.0100.07316.45
5.4.100.0030.07716.41
5.4.90.0070.07316.62
5.4.80.0030.07716.50
5.4.70.0030.07716.43
5.4.60.0070.07316.52
5.4.50.0000.07716.56
5.4.40.0000.06316.40
5.4.30.0130.07016.41
5.4.20.0030.07316.45
5.4.10.0070.07316.54
5.4.00.0030.07315.89
5.3.290.0000.08014.75
5.3.280.0030.07714.81
5.3.270.0030.07314.89
5.3.260.0000.08714.80
5.3.250.0070.07714.78
5.3.240.0030.07314.76
5.3.230.0070.07314.80
5.3.220.0070.07014.85
5.3.210.0030.08014.84
5.3.200.0030.07714.82
5.3.190.0030.08314.78
5.3.180.0100.07314.69
5.3.170.0000.07714.76
5.3.160.0070.07314.84
5.3.150.0000.07714.85
5.3.140.0130.06714.77
5.3.130.0000.07014.76
5.3.120.0070.07714.82
5.3.110.0030.06714.71
5.3.100.0070.06714.19
5.3.90.0100.05314.10
5.3.80.0070.06714.20
5.3.70.0030.07714.29
5.3.60.0070.07014.29
5.3.50.0130.07314.02
5.3.40.0070.07314.17
5.3.30.0100.06713.95
5.3.20.0070.07013.85
5.3.10.0030.07713.89
5.3.00.0070.07713.88

preferences:
47.08 ms | 401 KiB | 5 Q