国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

規(guī)則引擎RulerZ用法及實(shí)現(xiàn)原理解讀

edgardeng / 4158人閱讀

摘要:規(guī)則引擎用法及實(shí)現(xiàn)原理解讀廢話不多說(shuō),的官方地址是注意,本例中只拿普通數(shù)組做例子進(jìn)行分析簡(jiǎn)介是一個(gè)用實(shí)現(xiàn)的依賴包,目的是實(shí)現(xiàn)一個(gè)數(shù)據(jù)過(guò)濾規(guī)則引擎。

規(guī)則引擎RulerZ用法及實(shí)現(xiàn)原理解讀

廢話不多說(shuō),rulerz的官方地址是:https://github.com/K-Phoen/ru...

注意,本例中只拿普通數(shù)組做例子進(jìn)行分析
1. 簡(jiǎn)介

RulerZ是一個(gè)用php實(shí)現(xiàn)的composer依賴包,目的是實(shí)現(xiàn)一個(gè)數(shù)據(jù)過(guò)濾規(guī)則引擎。RulerZ不僅支持?jǐn)?shù)組過(guò)濾,也支持一些市面上常見(jiàn)的ORM,如Eloquent、Doctrine等,也支持Solr搜索引擎。
這是一個(gè)缺少中文官方文檔的開(kāi)源包,當(dāng)然由于star數(shù)比較少,可能作者也覺(jué)得沒(méi)必要。

2.安裝

在你的項(xiàng)目composer.json所在目錄下運(yùn)行:

composer require "kphoen/rulerz"
3.使用 - 過(guò)濾

現(xiàn)有數(shù)組如下:

$players = [
    ["pseudo" => "Joe",   "fullname" => "Joe la frite",             "gender" => "M", "points" => 2500],
    ["pseudo" => "Moe",   "fullname" => "Moe, from the bar!",       "gender" => "M", "points" => 1230],
    ["pseudo" => "Alice", "fullname" => "Alice, from... you know.", "gender" => "F", "points" => 9001],
];

初始化引擎:

use RulerZCompilerCompiler;
use RulerZTarget;
use RulerZRulerZ;

// compiler
$compiler = Compiler::create();

// RulerZ engine
$rulerz = new RulerZ(
    $compiler, [
        new TargetNativeNative([ // 請(qǐng)注意,這里是添加目標(biāo)編譯器,處理數(shù)組類型的數(shù)據(jù)源時(shí)對(duì)應(yīng)的是Native
            "length" => "strlen"
        ]),
    ]
);

創(chuàng)建一條規(guī)則:

$rule = "gender = :gender and points > :min_points"

將參數(shù)和規(guī)則交給引擎分析。

$parameters = [
    "min_points" => 30,
    "gender"     => "F",
];
$result = iterator_to_array(
        $rulerz->filter($players, $rule, $parameters) // the parameters can be omitted if empty
    );
// result 是一個(gè)過(guò)濾后的數(shù)組
array:1 [▼
  0 => array:4 [▼
    "pseudo" => "Alice"
    "fullname" => "Alice, from... you know."
    "gender" => "F"
    "points" => 9001
  ]
]
4.使用 - 判斷是否滿足規(guī)則
$rulerz->satisfies($player, $rule, $parameters);
// 返回布爾值,true表示滿足
5.底層代碼解讀

下面,讓我們看看從創(chuàng)建編譯器開(kāi)始,到最后出結(jié)果的過(guò)程中發(fā)生了什么。
1.Compiler::create();
這一步是實(shí)例化一個(gè)FileEvaluator類,這個(gè)類默認(rèn)會(huì)將本地的系統(tǒng)臨時(shí)目錄當(dāng)做下一步臨時(shí)類文件讀寫(xiě)所在目錄,文件類里包含一個(gè)has()方法和一個(gè)write()方法。文件類如下:


2.初始化RulerZ引擎,new RulerZ()
先看一下RulerZ的構(gòu)建方法:

    public function __construct(Compiler $compiler, array $compilationTargets = [])
    {
        $this->compiler = $compiler;

        foreach ($compilationTargets as $targetCompiler) {
            $this->registerCompilationTarget($targetCompiler);
        }
    }

這里的第一個(gè)參數(shù),就是剛剛的編譯器類,第二個(gè)是目標(biāo)編譯器類(實(shí)際處理數(shù)據(jù)源的),因?yàn)槲覀冞x擇的是數(shù)組,所以這里的目標(biāo)編譯器是Native,引擎會(huì)將這個(gè)目標(biāo)編譯類放到自己的屬性$compilationTargets

    public function registerCompilationTarget(CompilationTarget $compilationTarget): void
    {
        $this->compilationTargets[] = $compilationTarget;
    }

3.運(yùn)用filter或satisfies方法

這一點(diǎn)便是核心了。
以filter為例:

    public function filter($target, string $rule, array $parameters = [], array $executionContext = [])
    {
        $targetCompiler = $this->findTargetCompiler($target, CompilationTarget::MODE_FILTER);
        $compilationContext = $targetCompiler->createCompilationContext($target);
        $executor = $this->compiler->compile($rule, $targetCompiler, $compilationContext);

        return $executor->filter($target, $parameters, $targetCompiler->getOperators()->getOperators(), new ExecutionContext($executionContext));
    }

第一步會(huì)檢查目標(biāo)編譯器是否支持篩選模式。
第二步創(chuàng)建編譯上下文,這個(gè)一般統(tǒng)一是Context類實(shí)例

    public function createCompilationContext($target): Context
    {
        return new Context();
    }

第三步,執(zhí)行compiler的compile()方法

        public function compile(string $rule, CompilationTarget $target, Context $context): Executor
    {
        $context["rule_identifier"] = $this->getRuleIdentifier($target, $context, $rule);
        $context["executor_classname"] = "Executor_".$context["rule_identifier"];
        $context["executor_fqcn"] = "RulerZCompiledExecutorExecutor_".$context["rule_identifier"];

        if (!class_exists($context["executor_fqcn"], false)) {
            $compiler = function () use ($rule, $target, $context) {
                return $this->compileToSource($rule, $target, $context);
            };

            $this->evaluator->evaluate($context["rule_identifier"], $compiler);
        }

        return new $context["executor_fqcn"]();
    }
        protected function getRuleIdentifier(CompilationTarget $compilationTarget, Context $context, string $rule): string
    {
        return hash("crc32b", get_class($compilationTarget).$rule.$compilationTarget->getRuleIdentifierHint($rule, $context));
    }
    
        protected function compileToSource(string $rule, CompilationTarget $compilationTarget, Context $context): string
    {
        $ast = $this->parser->parse($rule);
        $executorModel = $compilationTarget->compile($ast, $context);

        $flattenedTraits = implode(PHP_EOL, array_map(function ($trait) {
            return "	"."use ".ltrim($trait, "").";";
        }, $executorModel->getTraits()));

        $extraCode = "";
        foreach ($executorModel->getCompiledData() as $key => $value) {
            $extraCode .= sprintf("private $%s = %s;".PHP_EOL, $key, var_export($value, true));
        }

        $commentedRule = str_replace(PHP_EOL, PHP_EOL."    // ", $rule);

        return <<getCompiledRule()};
    }
}
EXECUTOR;
    }

這段代碼會(huì)依照crc13算法生成一個(gè)哈希串和Executor拼接作為執(zhí)行器臨時(shí)類的名稱,并將執(zhí)行器相關(guān)代碼寫(xiě)進(jìn)上文提到的臨時(shí)目錄中去。生成的代碼如下:

// /private/var/folders/w_/sh4r42wn4_b650l3pc__fh7h0000gp/T/rulerz_executor_ff2800e8
 :min_points and points > :min_points
    protected function execute($target, array $operators, array $parameters)
    {
        return ($this->unwrapArgument($target["gender"]) == $parameters["gender"] && ($this->unwrapArgument($target["points"]) > $parameters["min_points"] && $this->unwrapArgument($target["points"]) > $parameters["min_points"]));
    }
}

這個(gè)臨時(shí)類文件就是最后要執(zhí)行過(guò)濾動(dòng)作的類。
FilterTrait中的filter方法是首先被執(zhí)行的,里面會(huì)根據(jù)execute返回的布爾值來(lái)判斷,是否通過(guò)迭代器返回符合條件的行。
execute方法就是根據(jù)具體的參數(shù)和操作符挨個(gè)判斷每行中對(duì)應(yīng)的cell是否符合判斷來(lái)返回true/false。

    public function filter($target, array $parameters, array $operators, ExecutionContext $context)
    {
        return IteratorTools::fromGenerator(function () use ($target, $parameters, $operators) {
            foreach ($target as $row) {
                $targetRow = is_array($row) ? $row : new ObjectContext($row);

                if ($this->execute($targetRow, $operators, $parameters)) {
                    yield $row;
                }
            }
        });
    }

satisfies和filter基本邏輯類似,只是最后satisfies是執(zhí)行單條判斷。

有一個(gè)問(wèn)題,我們的編譯器是如何知道我們?cè)O(shè)立的操作規(guī)則$rule的具體含義的,如何parse的?
這就涉及另一個(gè)問(wèn)題了,抽象語(yǔ)法樹(shù)(AST)。

Go further - 抽象語(yǔ)法樹(shù)

我們都知道php zend引擎在解讀代碼的過(guò)程中有一個(gè)過(guò)程是語(yǔ)法和詞法分析,這個(gè)過(guò)程叫做parser,中間會(huì)將代碼轉(zhuǎn)化為抽象語(yǔ)法樹(shù),這是引擎能夠讀懂代碼的關(guān)鍵步驟。

同樣,我們?cè)趯?xiě)一條規(guī)則字符串的時(shí)候,代碼如何能夠明白我們寫(xiě)的是什么呢?那就是抽象語(yǔ)法樹(shù)。

以上面的規(guī)則為例:

gender = :gender and points > :min_points

這里, =、and、>都是操作符,但是機(jī)器并不知道他們是操作符,也不知道其他字段是什么含義。

于是rulerz使用自己的語(yǔ)法模板。

首先是默認(rèn)定義了幾個(gè)操作符。

 function ($a, $b) {
                return sprintf("(%s && %s)", $a, $b);
            },
            "or" => function ($a, $b) {
                return sprintf("(%s || %s)", $a, $b);
            },
            "not" => function ($a) {
                return sprintf("!(%s)", $a);
            },
            "=" => function ($a, $b) {
                return sprintf("%s == %s", $a, $b);
            },
            "is" => function ($a, $b) {
                return sprintf("%s === %s", $a, $b);
            },
            "!=" => function ($a, $b) {
                return sprintf("%s != %s", $a, $b);
            },
            ">" => function ($a, $b) {
                return sprintf("%s > %s", $a, $b);
            },
            ">=" => function ($a, $b) {
                return sprintf("%s >= %s", $a, $b);
            },
            "<" => function ($a, $b) {
                return sprintf("%s < %s", $a, $b);
            },
            "<=" => function ($a, $b) {
                return sprintf("%s <= %s", $a, $b);
            },
            "in" => function ($a, $b) {
                return sprintf("in_array(%s, %s)", $a, $b);
            },
        ];

        $defaultOperators = [
            "sum" => function () {
                return array_sum(func_get_args());
            },
        ];

        $definitions = new Definitions($defaultOperators, $defaultInlineOperators);

        return $definitions->mergeWith($customOperators);
    }
}

在RulerZParserParser中,有如下方法:

public function parse($rule)
{
    if ($this->parser === null) {
        $this->parser = CompilerLlk::load(
            new FileRead(__DIR__."/../Grammar.pp")
        );
    }

    $this->nextParameterIndex = 0;

    return $this->visit($this->parser->parse($rule));
}

這里要解讀一個(gè)核心語(yǔ)法文件Grammar.pp,Pascal語(yǔ)法腳本:

//
// Hoa
//
//
// @license
//
// New BSD License
//
// Copyright ? 2007-2015, Ivan Enderlin. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Hoa nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Inspired from HoaRulerGrammar.
//
// @author     Stéphane Py 
// @author     Ivan Enderlin 
// @author     Kévin Gomez 
// @copyright  Copyright ? 2007-2015 Stéphane Py, Ivan Enderlin, Kévin Gomez.
// @license    New BSD License


%skip   space         s

// Scalars.
%token  true          (?i)true
%token  false         (?i)false
%token  null          (?i)null

// Logical operators
%token  not           (?i)not
%token  and           (?i)and
%token  or            (?i)or
%token  xor           (?i)xor

// Value
%token  string        ("|")(.*?)(? logical_operation() #operation )?

operand:
    ::parenthesis_:: logical_operation() ::_parenthesis::
  | value()

parameter:
    
  | 

value:
    ::not:: logical_operation() #not
  |  |  |  |  |  | 
  | parameter()
  | variable()
  | array_declaration()
  | function_call()

variable:
     ( object_access() #variable_access )*

object_access:
    ::dot::  #attribute_access

#array_declaration:
    ::bracket_:: value() ( ::comma:: value() )* ::_bracket::

#function_call:
     ::parenthesis_::
    ( logical_operation() ( ::comma:: logical_operation() )* )?
    ::_parenthesis::

上面Llk::load方法會(huì)加載這個(gè)基礎(chǔ)語(yǔ)法內(nèi)容并解析出片段tokens,tokens解析的邏輯就是正則匹配出我們需要的一些操作符和基礎(chǔ)標(biāo)識(shí)符,并將對(duì)應(yīng)的正則表達(dá)式提取出來(lái):

array:1 [▼
  "default" => array:20 [▼
    "skip" => "s"
    "true" => "(?i)true"
    "false" => "(?i)false"
    "null" => "(?i)null"
    "not" => "(?i)not"
    "and" => "(?i)and"
    "or" => "(?i)or"
    "xor" => "(?i)xor"
    "string" => "("|")(.*?)(? "-?d+.d+"
    "integer" => "-?d+"
    "parenthesis_" => "("
    "_parenthesis" => ")"
    "bracket_" => "["
    "_bracket" => "]"
    "comma" => ","
    "dot" => "."
    "positional_parameter" => "?"
    "named_parameter" => ":[a-z-A-Z0-9_]+"
    "identifier" => "[^s()[],.]+"
  ]
]

這一步也會(huì)生成一個(gè)rawRules

array:10 [▼
  "#expression" => " logical_operation()"
  "logical_operation" => " operation() ( ( ::and:: #and | ::or:: #or | ::xor:: #xor ) logical_operation() )?"
  "operation" => " operand() (  logical_operation() #operation )?"
  "operand" => " ::parenthesis_:: logical_operation() ::_parenthesis:: | value()"
  "parameter" => "  | "
  "value" => " ::not:: logical_operation() #not |  |  |  |  |  |  | parameter() | variable() | array_declaration() | function_call( ?"
  "variable" => "  ( object_access() #variable_access )*"
  "object_access" => " ::dot::  #attribute_access"
  "#array_declaration" => " ::bracket_:: value() ( ::comma:: value() )* ::_bracket::"
  "#function_call" => "  ::parenthesis_:: ( logical_operation() ( ::comma:: logical_operation() )* )? ::_parenthesis::"
]

這個(gè)rawRules會(huì)通過(guò)analyzer類的analyzeRules方法解析替換里面的::表示的空位,根據(jù)$_ppLexemes屬性的值,CompilerLlkLexer()詞法解析器會(huì)將rawRules數(shù)組每一個(gè)元素解析放入雙向鏈表?xiàng)?SplStack)中,然后再通過(guò)對(duì)該棧插入和刪除操作,形成一個(gè)包含所有操作符和token實(shí)例的數(shù)組$rules。

array:54 [▼
  0 => Concatenation {#64 ?}
  "expression" => Concatenation {#65 ▼
    #_name: "expression"
    #_children: array:1 [▼
      0 => 0
    ]
    #_nodeId: "#expression"
    #_nodeOptions: []
    #_defaultId: "#expression"
    #_defaultOptions: []
    #_pp: " logical_operation()"
    #_transitional: false
  }
  2 => Token {#62 ?}
  3 => Concatenation {#63 ▼
    #_name: 3
    #_children: array:1 [▼
      0 => 2
    ]
    #_nodeId: "#and"
    #_nodeOptions: []
    #_defaultId: null
    #_defaultOptions: []
    #_pp: null
    #_transitional: true
  }
  4 => Token {#68 ?}
  5 => Concatenation {#69 ?}
  6 => Token {#70 ?}
  7 => Concatenation {#71 ?}
  8 => Choice {#72 ?}
  9 => Concatenation {#73 ?}
  10 => Repetition {#74 ?}
  "logical_operation" => Concatenation {#75 ?}
  12 => Token {#66 ?}
  13 => Concatenation {#67 ?}
  14 => Repetition {#78 ?}
  "operation" => Concatenation {#79 ?}
  16 => Token {#76 ?}
  17 => Token {#77 ?}
  18 => Concatenation {#82 ?}
  "operand" => Choice {#83 ?}
  20 => Token {#80 ?}
  21 => Token {#81 ▼
    #_tokenName: "named_parameter"
    #_namespace: null
    #_regex: null
    #_ast: null
    #_value: null
    #_kept: true
    #_unification: -1
    #_name: 21
    #_children: null
    #_nodeId: null
    #_nodeOptions: []
    #_defaultId: null
    #_defaultOptions: []
    #_pp: null
    #_transitional: true
  }
  "parameter" => Choice {#86 ?}
  23 => Token {#84 ?}
  24 => Concatenation {#85 ?}
  25 => Token {#89 ?}
  26 => Token {#90 ?}
  27 => Token {#91 ?}
  28 => Token {#92 ?}
  29 => Token {#93 ?}
  30 => Token {#94 ?}
  "value" => Choice {#95 ?}
  32 => Token {#87 ?}
  33 => Concatenation {#88 ?}
  34 => Repetition {#98 ?}
  "variable" => Concatenation {#99 ?}
  36 => Token {#96 ?}
  37 => Token {#97 ?}
  "object_access" => Concatenation {#102 ?}
  39 => Token {#100 ?}
  40 => Token {#101 ?}
  41 => Concatenation {#105 ?}
  42 => Repetition {#106 ?}
  43 => Token {#107 ?}
  "array_declaration" => Concatenation {#108 ?}
  45 => Token {#103 ?}
  46 => Token {#104 ?}
  47 => Token {#111 ?}
  48 => Concatenation {#112 ?}
  49 => Repetition {#113 ?}
  50 => Concatenation {#114 ?}
  51 => Repetition {#115 ?}
  52 => Token {#116 ?}
  "function_call" => Concatenation {#117 ?}
]

然后返回HoaCompilerLlkParser實(shí)例,這個(gè)實(shí)例有一個(gè)parse方法,正是此方法構(gòu)成了一個(gè)語(yǔ)法樹(shù)。

public function parse($text, $rule = null, $tree = true)
    {
        $k = 1024;

        if (isset($this->_pragmas["parser.lookahead"])) {
            $k = max(0, intval($this->_pragmas["parser.lookahead"]));
        }

        $lexer                = new Lexer($this->_pragmas);
        $this->_tokenSequence = new IteratorBuffer(
            $lexer->lexMe($text, $this->_tokens),
            $k
        );
        $this->_tokenSequence->rewind();

        $this->_errorToken = null;
        $this->_trace      = [];
        $this->_todo       = [];

        if (false === array_key_exists($rule, $this->_rules)) {
            $rule = $this->getRootRule();
        }

        $closeRule   = new RuleEkzit($rule, 0);
        $openRule    = new RuleEntry($rule, 0, [$closeRule]);
        $this->_todo = [$closeRule, $openRule];

        do {
            $out = $this->unfold();

            if (null  !== $out &&
                "EOF" === $this->_tokenSequence->current()["token"]) {
                break;
            }

            if (false === $this->backtrack()) {
                $token  = $this->_errorToken;

                if (null === $this->_errorToken) {
                    $token = $this->_tokenSequence->current();
                }

                $offset = $token["offset"];
                $line   = 1;
                $column = 1;

                if (!empty($text)) {
                    if (0 === $offset) {
                        $leftnl = 0;
                    } else {
                        $leftnl = strrpos($text, "
", -(strlen($text) - $offset) - 1) ?: 0;
                    }

                    $rightnl = strpos($text, "
", $offset);
                    $line    = substr_count($text, "
", 0, $leftnl + 1) + 1;
                    $column  = $offset - $leftnl + (0 === $leftnl);

                    if (false !== $rightnl) {
                        $text = trim(substr($text, $leftnl, $rightnl - $leftnl), "
");
                    }
                }

                throw new CompilerExceptionUnexpectedToken(
                    "Unexpected token "%s" (%s) at line %d and column %d:" .
                    "
" . "%s" . "
" . str_repeat(" ", $column - 1) . "↑",
                    0,
                    [
                        $token["value"],
                        $token["token"],
                        $line,
                        $column,
                        $text
                    ],
                    $line,
                    $column
                );
            }
        } while (true);

        if (false === $tree) {
            return true;
        }

        $tree = $this->_buildTree();

        if (!($tree instanceof TreeNode)) {
            throw new CompilerException(
                "Parsing error: cannot build AST, the trace is corrupted.",
                1
            );
        }

        return $this->_tree = $tree;
    }

我們得到的一個(gè)完整的語(yǔ)法樹(shù)是這樣的:

Rule {#120 ▼
  #_root: Operator {#414 ▼
    #_name: "and"
    #_arguments: array:2 [▼
      0 => Operator {#398 ▼
        #_name: "="
        #_arguments: array:2 [▼
          0 => Context {#396 ▼
            #_id: "gender"
            #_dimensions: []
          }
          1 => Parameter {#397 ▼
            -name: "gender"
          }
        ]
        #_function: false
        #_laziness: false
        #_id: null
        #_dimensions: []
      }
      1 => Operator {#413 ▼
        #_name: "and"
        #_arguments: array:2 [▼
          0 => Operator {#401 ▼
            #_name: ">"
            #_arguments: array:2 [▼
              0 => Context {#399 ?}
              1 => Parameter {#400 ?}
            ]
            #_function: false
            #_laziness: false
            #_id: null
            #_dimensions: []
          }
          1 => Operator {#412 ?}
        ]
        #_function: false
        #_laziness: true
        #_id: null
        #_dimensions: []
      }
    ]
    #_function: false
    #_laziness: true
    #_id: null
    #_dimensions: []
  }
}

這里有根節(jié)點(diǎn)、子節(jié)點(diǎn)、操作符參數(shù)以及HoaRulerModelOperator實(shí)例。

這時(shí)$executorModel = $compilationTarget->compile($ast, $context);就可以通過(guò)NativeVisitor的visit方法對(duì)這個(gè)語(yǔ)法樹(shù)進(jìn)行訪問(wèn)和分析了。

這一步走的是visitOperator()

    /**
     * {@inheritdoc}
     */
    public function visitOperator(ASTOperator $element, &$handle = null, $eldnah = null)
    {
        $operatorName = $element->getName();

        // the operator does not exist at all, throw an error before doing anything else.
        if (!$this->operators->hasInlineOperator($operatorName) && !$this->operators->hasOperator($operatorName)) {
            throw new OperatorNotFoundException($operatorName, sprintf("Operator "%s" does not exist.", $operatorName));
        }

        // expand the arguments
        $arguments = array_map(function ($argument) use (&$handle, $eldnah) {
            return $argument->accept($this, $handle, $eldnah);
        }, $element->getArguments());

        // and either inline the operator call
        if ($this->operators->hasInlineOperator($operatorName)) {
            $callable = $this->operators->getInlineOperator($operatorName);

            return call_user_func_array($callable, $arguments);
        }

        $inlinedArguments = empty($arguments) ? "" : ", ".implode(", ", $arguments);

        // or defer it.
        return sprintf("call_user_func($operators["%s"]%s)", $operatorName, $inlinedArguments);
    }

那么編譯好的規(guī)則可以通過(guò)以下方式得到:

$executorModel->getCompiledRule()
// 規(guī)則就是 $this->unwrapArgument($target["gender"]) == $parameters["gender"] && ($this->unwrapArgument($target["points"]) > $parameters["min_points"] && $this->unwrapArgument($target["points"]) > $parameters["min_points"])

自定義一個(gè)操作器

由于官方文檔太老且無(wú)更,所以如果你按照他的文檔去自定義的話會(huì)哭暈,這里給出一個(gè)對(duì)應(yīng)的示例。

$compiler = Compiler::create();
$rulerz = new RulerZ($compiler, [
    new Native([
        "length" => "strlen"
    ],[
        "contains" => function ($a, $b) {
            return sprintf("strstr(%s, %s)", $a, $b);
        }
    ])
]);

上文中contains表示的是用系統(tǒng)函數(shù)strstr()來(lái)判斷$a中是否包含$b字符,由于編譯后的代碼是通過(guò)字符串生成的,所以你在這個(gè)匿名函數(shù)中必須要用字符串表達(dá)判斷邏輯,這也是其缺點(diǎn)之一。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/30936.html

相關(guān)文章

  • Vue 進(jìn)階系列(二)之插件原理實(shí)現(xiàn)

    摘要:示例輸出第一步先不考慮插件,在已有的中是沒(méi)有這個(gè)公共方法的,如果要簡(jiǎn)單實(shí)現(xiàn)的話可以通過(guò)鉤子函數(shù)來(lái),即在里面驗(yàn)證邏輯。按照插件的開(kāi)發(fā)流程,應(yīng)該有一個(gè)公開(kāi)方法,在里面使用全局的方法添加一些組件選項(xiàng),方法包含一個(gè)鉤子函數(shù),在鉤子函數(shù)中驗(yàn)證。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo))showImg(https://segmen...

    wuaiqiu 評(píng)論0 收藏0
  • 你和阿里資深架構(gòu)師之間,差的不僅僅是年齡(進(jìn)階必看)

    摘要:導(dǎo)讀閱讀本文需要有足夠的時(shí)間,筆者會(huì)由淺到深帶你一步一步了解一個(gè)資深架構(gòu)師所要掌握的各類知識(shí)點(diǎn),你也可以按照文章中所列的知識(shí)體系對(duì)比自身,對(duì)自己進(jìn)行查漏補(bǔ)缺,覺(jué)得本文對(duì)你有幫助的話,可以點(diǎn)贊關(guān)注一下。目錄一基礎(chǔ)篇二進(jìn)階篇三高級(jí)篇四架構(gòu)篇五擴(kuò) 導(dǎo)讀:閱讀本文需要有足夠的時(shí)間,筆者會(huì)由淺到深帶你一步一步了解一個(gè)資深架構(gòu)師所要掌握的各類知識(shí)點(diǎn),你也可以按照文章中所列的知識(shí)體系對(duì)比自身,對(duì)自己...

    huaixiaoz 評(píng)論0 收藏0
  • 從 ++[[]][+[]]+[+[]]==10? 深入淺出弱類型 JS 的隱式轉(zhuǎn)換

    摘要:與此相對(duì),強(qiáng)類型語(yǔ)言的類型之間不一定有隱式轉(zhuǎn)換。三為什么是弱類型弱類型相對(duì)于強(qiáng)類型來(lái)說(shuō)類型檢查更不嚴(yán)格,比如說(shuō)允許變量類型的隱式轉(zhuǎn)換,允許強(qiáng)制類型轉(zhuǎn)換等等。在中,加性運(yùn)算符有大量的特殊行為。 從++[[]][+[]]+[+[]]==10?深入淺出弱類型JS的隱式轉(zhuǎn)換 本文純屬原創(chuàng)? 如有雷同? 純屬抄襲? 不甚榮幸! 歡迎轉(zhuǎn)載! 原文收錄在【我的GitHub博客】,覺(jué)得本文寫(xiě)的不算爛的...

    miya 評(píng)論0 收藏0
  • 神策數(shù)據(jù)關(guān)海南:營(yíng)銷策略引擎解讀,以平臺(tái)化構(gòu)建營(yíng)銷新生態(tài)

    摘要:神策數(shù)據(jù)關(guān)海南營(yíng)銷策略引擎解讀,以平臺(tái)化構(gòu)建營(yíng)銷新生態(tài)計(jì)算引擎圖片神策數(shù)據(jù)關(guān)海南營(yíng)銷策略引擎解讀,以平臺(tái)化構(gòu)建營(yíng)銷新生態(tài)微信在神策數(shù)據(jù)驅(qū)動(dòng)大會(huì)現(xiàn)場(chǎng),神策營(yíng)銷云架構(gòu)師關(guān)海南發(fā)表了題為營(yíng)銷策略引擎的技術(shù)演進(jìn)的演講。 ??在??神策 2021 數(shù)據(jù)驅(qū)動(dòng)大會(huì)??現(xiàn)場(chǎng),神策營(yíng)銷云架構(gòu)師關(guān)海南發(fā)表了題為《營(yíng)銷策略引擎(Express)...

    番茄西紅柿 評(píng)論0 收藏2637
  • 學(xué)習(xí)JVM必看書(shū)籍

    學(xué)習(xí)JVM的相關(guān)資料 《深入理解Java虛擬機(jī)——JVM高級(jí)特性與最佳實(shí)踐(第2版)》 showImg(https://segmentfault.com/img/bVbsqF5?w=200&h=200); 基于最新JDK1.7,圍繞內(nèi)存管理、執(zhí)行子系統(tǒng)、程序編譯與優(yōu)化、高效并發(fā)等核心主題對(duì)JVM進(jìn)行全面而深入的分析,深刻揭示JVM的工作原理。以實(shí)踐為導(dǎo)向,通過(guò)大量與實(shí)際生產(chǎn)環(huán)境相結(jié)合的案例展示了解...

    shaonbean 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<