-
-
Save DaveRandom/c23d394cb4f1af211b94 to your computer and use it in GitHub Desktop.
Class for resolving standard PHP bitwise expressions using integers and/or E_* error constants to integers. Should work with any value allowed in php.ini
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Class for resolving standard PHP bitwise expressions using integers | |
* and/or E_* error constants to integers. Should work with any value | |
* allowed in php.ini | |
* | |
* PHP version 5.3 | |
* | |
* @author Chris Wright <info@daverandom.com> | |
* @copyright Copyright (c) 2013 Chris Wright | |
* @license http://www.opensource.org/licenses/mit-license.html MIT License | |
* @version 1.0 | |
*/ | |
/** | |
* Class for resolving standard PHP bitwise expressions using integers | |
* and/or E_* error constants to integers. Should work with any value | |
* allowed in php.ini | |
* | |
* @author Chris Wright <info@daverandom.com> | |
*/ | |
class ErrorExpressionResolver | |
{ | |
/** | |
* Recusively resolve nested expressions to a flat expression | |
* | |
* @param string $subject The subject expression to resolve | |
* | |
* @return int The value the expression represents | |
* | |
* @throws \InvalidArgumentException When the subject expression is invalid | |
*/ | |
private function resolveGroups($subject) | |
{ | |
return preg_replace_callback( | |
'/~?[ \t]*\((?:(?>[^()]+)|(?R))*\)/', | |
array($this, 'groupCallback'), | |
trim($subject) | |
); | |
} | |
/** | |
* Callback for resolving a single nested expression | |
* | |
* @param array $matches A PCRE match array for the matched expression | |
* | |
* @return string The value the expression represents, converted to a string | |
* | |
* @throws \InvalidArgumentException When the subject expression is invalid | |
*/ | |
private function groupCallback($matches) | |
{ | |
$isNegated = $matches[0][0] === '~'; | |
if ($isNegated) { | |
$matches[0] = ltrim($matches[0], "\t\r\n\x00 ~"); | |
} | |
if ($matches[0][0] === '(') { | |
$matches[0] = substr(rtrim($matches[0]), 1, -1); | |
} | |
$result = $this->resolve($matches[0]); | |
if ($isNegated) { | |
$result = ~((int) $result); | |
} | |
return (string) $result; | |
} | |
/** | |
* Resolve a single string operand to an integer | |
* | |
* @param string $operand The operand | |
* | |
* @return int The value the operand represents | |
* | |
* @throws \InvalidArgumentException When the operand cannot be resolved | |
*/ | |
private function resolveOperand($operand) | |
{ | |
$operand = trim($operand); | |
$isNegated = $operand[0] === '~'; | |
if ($isNegated) { | |
$operand = ltrim($operand, "\t\r\n\x00 ~"); | |
} | |
if (preg_match('/^-?\d+$/', $operand)) { | |
$operand = (int) $operand; | |
} else if (substr($operand, 0, 2) === 'E_' && defined($operand)) { | |
$operand = (int) constant($operand); | |
} else { | |
throw new \InvalidArgumentException('Invalid operand: ' . $operand); | |
} | |
if ($isNegated) { | |
$operand = ~$operand; | |
} | |
return $operand; | |
} | |
/** | |
* Perform a bitwise operation on two operands | |
* | |
* @param int $left The operand on the left side of the operation | |
* @param int $operator The operator used in the operation | |
* @param int $right The operand on the right side of the operation | |
* | |
* @return int The result of the operation | |
* | |
* @throws \InvalidArgumentException When the operator in invalid | |
*/ | |
private function doOperation($left, $operator, $right) | |
{ | |
switch (trim($operator)) { | |
case '|': | |
$result = $left | $right; | |
break; | |
case '&': | |
$result = $left & $right; | |
break; | |
case '^': | |
$result = $left ^ $right; | |
break; | |
default: | |
throw new \InvalidArgumentException('Unsupported operator: ' . $operator); | |
} | |
return $result; | |
} | |
/** | |
* Evaluate a flat expression represented as a string | |
* | |
* @param string $subject The subject expression to evaluate | |
* | |
* @return int The result of the operation | |
* | |
* @throws \InvalidArgumentException When any of the operands or operators is invalid | |
*/ | |
private function evaluateFlatExpression($subject) | |
{ | |
$result = 0; | |
$operator = '|'; | |
$parts = preg_split( | |
'/[\t ]*(\S+)[\t ]*/', | |
$subject, | |
-1, | |
PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY | |
); | |
for ($i = 0; isset($parts[$i]); $i += 2) { | |
$operand = $this->resolveOperand($parts[$i]); | |
$result = $this->doOperation($result, $operator, $operand); | |
if (isset($parts[$i + 1])) { | |
$operator = $parts[$i + 1]; | |
} | |
} | |
return $result; | |
} | |
/** | |
* Resolve an expression to an integer | |
* | |
* @param string $subject The subject expression to resolve | |
* | |
* @return int The value the expression represents | |
* | |
* @throws \InvalidArgumentException When the subject expression is invalid | |
*/ | |
public function resolve($subject) | |
{ | |
$flat = $this->resolveGroups($subject); | |
$result = $this->evaluateFlatExpression($flat); | |
return $result; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$subject = 'E_ALL & ~(E_NOTICE | E_WARNING | E_STRICT | E_CORE_WARNING | E_COMPILE_WARNING | E_USER_WARNING | E_DEPRECATED)'; | |
$resolver = new ErrorExpressionResolver; | |
var_dump($resolver->resolve($subject)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment