表达式语法

3.4 版本
维护中的版本

ExpressionLanguage组件使用了一种特殊的语法,即基于Twig的表达式语法。在本文档中,你可以找到所有受支持的语法。

受支持的字符 

表达式组件支持:

  • strings(字符串) - 单引和双引号 (如 'hello')
  • numbers(数字) - 如 103
  • arrays(数组) - using JSON-like notation (如 [1, 2])
  • hashes(键值型数组) - using JSON-like notation (如 { foo: 'bar' })
  • booleans(布尔值) - true and false
  • null - null

在字符串中,反斜杠(\)必须通过4个反斜杠(\\\\)来转义,而在正则表达式中,需要用8个反斜杠(\\\\\\\\)来转义:

1
2
echo $language->evaluate('"\\\\"'); // prints \
$language->evaluate('"a\\\\b" matches "/^a\\\\\\\\b$/"'); // returns true

表达式中的控制符(control characters,比如\n)将被空格替代。为避免出现这种情况,使用单斜杠来转义(如\\n

操作对象 

当把对象传到表达式中时,你可以使用不同的方法在对象中访问属性和调用方法。

访问公有属性 

使用 . 语法可以访问对象的公有属性,类似于JavaScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Apple
{
    public $variety;
}
 
$apple = new Apple();
$apple->variety = 'Honeycrisp';
 
var_dump($language->evaluate(
    'fruit.variety',
    array(
        'fruit' => $apple,
    )
));

这将输出 Honeycrisp

调用方法 

. 语法也可以调用对象方法,类似于JavaScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Robot
{
    public function sayHi($times)
    {
        $greetings = array();
        for ($i = 0; $i < $times; $i++) {
            $greetings[] = 'Hi';
        }
 
        return implode(' ', $greetings).'!';
    }
}
 
$robot = new Robot();
 
var_dump($language->evaluate(
    'robot.sayHi(3)',
    array(
        'robot' => $robot,
    )
));

这将输出 Hi Hi Hi!

使用函数 

使用与PHP和JavaScript相同的语法,你可以在表达式中使用已注册的函数。ExpressionLanguage组件内置了一个默认函数:constant(),它将返回PHP常量的值:

1
2
3
4
5
define('DB_USER', 'root');
 
var_dump($language->evaluate(
    'constant("DB_USER")'
));

它会输出root

要了解如何注册你自己的函数,参考 扩展ExpressionLanguage类

使用数组 

如果你传递一个数组到表达式中,使用 [] 语法来访问数组的键,类似于JavaScript:

1
2
3
4
5
6
7
8
$data = array('life' => 10, 'universe' => 10, 'everything' => 22);
 
var_dump($language->evaluate(
    'data["life"] + data["universe"] + data["everything"]',
    array(
        'data' => $data,
    )
));

这将输出 42

受支持的操作符 

算术运算符 

  • + (加)
  • - (减)
  • * (乘)
  • / (除)
  • % (模)
  • ** (幂)

例如:

1
2
3
4
5
6
7
8
var_dump($language->evaluate(
    'life + universe + everything',
    array(
        'life' => 10,
        'universe' => 10,
        'everything' => 22,
    )
));

这将输出 42

位运算符 

  • & (和)
  • | (或)
  • ^ (异或)

比较运算符 

  • == (等于)
  • === (全等)
  • != (不等于)
  • !== (不全等)
  • < (小于)
  • > (大于)
  • <= (小于等于)
  • >= (大于等于)
  • matches (正则匹配)

要测试一个字符串 与某个正则相匹配,使用逻辑not运算符,配合matches操作符:

1
$language->evaluate('not ("foo" matches "/bar/")'); // returns true

你必须使用括号,因为一元运算符not拥有高于二元操作符matches的优先级。

例程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ret1 = $language->evaluate(
    'life == everything',
    array(
        'life' => 10,
        'universe' => 10,
        'everything' => 22,
    )
);
 
$ret2 = $language->evaluate(
    'life > everything',
    array(
        'life' => 10,
        'universe' => 10,
        'everything' => 22,
    )
);

两个变量都将被设置为false

逻辑运算符 

  • not!
  • and&&
  • or||
1
2
3
4
5
6
7
8
$ret = $language->evaluate(
    'life < universe or life < everything',
    array(
        'life' => 10,
        'universe' => 10,
        'everything' => 22,
    )
);

$ret变量将被设置为true

字符串操作符 

  • ~ (连接)

例程:

1
2
3
4
5
6
7
var_dump($language->evaluate(
    'firstName~" "~lastName',
    array(
        'firstName' => 'Arthur',
        'lastName' => 'Dent',
    )
));

这将输出Arthur Dent

数组运算符 

  • in (包含)
  • not in (不包含)

例程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class User
{
    public $group;
}
 
$user = new User();
$user->group = 'human_resources';
 
$inGroup = $language->evaluate(
    'user.group in ["human_resources", "marketing"]',
    array(
        'user' => $user,
    )
);

$inGroup变量将被计算成true

数字运算符 

  • .. (范围)

例程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class User
{
    public $age;
}
 
$user = new User();
$user->age = 34;
 
$language->evaluate(
    'user.age in 18..45',
    array(
        'user' => $user,
    )
);

这将被计算成 true,因为 user.age 是一个从 1845 的范围。

三目运算符 

  • foo ? 'yes' : 'no'
  • foo ?: 'no' (equal to foo ? foo : 'no')
  • foo ? 'yes' (equal to foo ? 'yes' : '')

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)