该方法适合所有的编程语言
背景:
想用字符串来当作if的条件,想用在auth权限管理里面
虽然,php的evel()函数可以实现;但是,毕竟不安全,那就自己实现一个简单的吧!
目标:
支持以下运算符:
>=
>
<=
<
==
!=
&&
||
支持中文
缺点:
不支持括号,所以我称之为简单的实现
<?php
// $str就是要运算的字符串
// $data就是数据库查询出来的数据数组
// 如果只想要直接运算$str的,而不用data变量替换填充的,就可以改造下:
// 首先$str不包含变量,并且strOp函数只有$str一个参数,最后将[数据填充]步骤去掉即可
//$str = "1||score<50 && name==a的bd 的c && score<100 || name!=abc && 30 > 100";
//$str = "score<50 && name==a的bd 的c && score<100 || name!=abc && 30 > 100";
$str = "score<50 && name==a的bd 的c && score<100 || name!=abc && 30 > 100||1";
$data = ['score'=>30, 'name'=>'abc'];
var_dump(strOp($str, $data)); // 结果为bool(true);
// 字符串运算
function strOp($str, $data)
{
// 运算符号
$opStr = '>=><=<&&==||!=';
// 去除空格
$str = str_replace(" ", "", $str);
$str = preg_replace('/[\n\r\t]/','',$str);
// 数据填充,得到运算字符串
foreach($data as $k => $v) {
$str = str_replace($k, $v, $str);
}
// 运算字符串转数组
$len = mb_strlen($str, 'utf-8');
$strArr = [];
for ($i = 0; $i < $len; $i++) {
$strArr[] = mb_substr($str, $i, 1, 'utf-8');
}
// 提取有效运算符
$isContinue = false;
$opArr = []; // 所有要运算的符号
$valArr = []; // 要进行运算的值
$opRes = []; // 除&&、||外的运算结果
$andOrOpArr = []; // &&、||运算符号
$record = 0; // 字符串截取的起点标记
for ($i = 0; $i < $len; $i++) {
if (strpos($opStr, $strArr[$i]) !== false) {
if (strpos($opStr, $strArr[$i] . $strArr[$i+1]) !== false) {
$isContinue = true;
$opArr[] = $strArr[$i] . $strArr[$i+1];
$valArr[] = getValStr($strArr, $record, $i - $record);
$record = $i + 2;
} else {
if ($isContinue) {
$isContinue = false;
continue;
} else if (strpos('=&|', $strArr[$i]) === false) {
$opArr[] = $strArr[$i];
$valArr[] = getValStr($strArr, $record, $i - $record);
$record = $i + 1;
}
}
}
}
$valArr[] = getValStr($strArr, $record, $len - $record);
// 运算除&&、||外的符号,并存储结果
foreach ($opArr as $k => $v) {
if (strpos('&&||', $v) !== false) {
$andOrOpArr[] = $v;
if ($v == '||' && $k == 0) {
// 第一个符号为||,如0||...的情况
$opRes[] = array_shift($valArr);
}
if ($v == '||' && count($valArr) == 1) {
// 最后一个符号为||,如:...||0的情况
$opRes[] = array_shift($valArr);
}
} else {
$left = array_shift($valArr);
$right = array_shift($valArr);
$opRes[] = opRes($v, $left, $right);
}
}
// 判断$andOrOpArr的情况,有没&&,有没||,是否为空
// 如果$andOrOpArr为空,则直接返回$opRes[0]
// 如果$andOrOpArr只有&&
// 如果$andOrOpArr只有||
// 如果$andOrOpArr有&&也有||
$res = false;
if (empty($andOrOpArr)) {
// 没有&&和||
$res = array_shift($opRes);
} else if (in_array('&&', $andOrOpArr, true) && !in_array('||', $andOrOpArr, true)) {
// 只有&&,没有||
$res = true;
foreach ($opRes as $v) {
if (!$v) {
$res = false;
break;
}
}
} else if (!in_array('&&', $andOrOpArr, true) && in_array('||', $andOrOpArr, true)) {
// 没有&&,只有||
foreach ($opRes as $v) {
if ($v) {
$res = true;
break;
}
}
} else if (in_array('&&', $andOrOpArr, true) && in_array('||', $andOrOpArr, true)) {
// 既有&&,也有||
// 最后要进行运算||的值
$lastOrOpValArr = [];
// 运算&&,并存储结果(剩下的全是&&和||运算,而&&优先级高于||)
foreach ($andOrOpArr as $k => $v) {
if ($v == '&&') {
$left = array_shift($opRes);
$right = array_shift($opRes);
array_unshift($opRes, $left && $right);
} else {
$lastOrOpValArr[] = array_shift($opRes);
}
if (count($opRes) == 1) {
$lastOrOpValArr[] = array_shift($opRes);
}
}
// 运算||(剩下的全是||运算)
foreach ($lastOrOpValArr as $v) {
if ($v) {
$res = true;
break;
}
}
}
return $res; // 最终结果
}
// 运算函数
function opRes($str, $left, $right)
{
$res = false;
switch ($str) {
case '>=':
$res = $left >= $right;
break;
case '>':
$res = $left > $right;
break;
case '<=':
$res = $left <= $right;
break;
case '<':
$res = $left < $right;
break;
case '==':
$res = $left == $right;
break;
case '!=':
$res = $left != $right;
break;
}
return $res;
}
// 获取val值
function getValStr($arr, $start, $length)
{
$val = '';
for ($n = $start; $n < $start + $length; $n++) {
$val .= $arr[$n];
}
return $val;
}
|