SqlParser\Components\Expression::parse PHP Méthode

parse() public static méthode

field First field to be filled. If this is not specified, it takes the value of parseField. parseField Specifies the type of the field parsed. It may be database, table or column. These expressions may not include parentheses. breakOnAlias If not empty, breaks when the alias occurs (it is not included). breakOnParentheses If not empty, breaks when the first parentheses occurs. parenthesesDelimited If not empty, breaks after last parentheses occurred.
public static parse ( Parser $parser, TokensList $list, array $options = [] ) : Expression
$parser SqlParser\Parser The parser that serves as context.
$list SqlParser\TokensList The list of tokens that are being parsed.
$options array Parameters for parsing.
Résultat Expression
    public static function parse(Parser $parser, TokensList $list, array $options = array())
    {
        $ret = new Expression();
        /**
         * Whether current tokens make an expression or a table reference.
         *
         * @var bool $isExpr
         */
        $isExpr = false;
        /**
         * Whether a period was previously found.
         *
         * @var bool $dot
         */
        $dot = false;
        /**
         * Whether an alias is expected. Is 2 if `AS` keyword was found.
         *
         * @var bool $alias
         */
        $alias = false;
        /**
         * Counts brackets.
         *
         * @var int $brackets
         */
        $brackets = 0;
        /**
         * Keeps track of the last two previous tokens.
         *
         * @var Token[] $prev
         */
        $prev = array(null, null);
        // When a field is parsed, no parentheses are expected.
        if (!empty($options['parseField'])) {
            $options['breakOnParentheses'] = true;
            $options['field'] = $options['parseField'];
        }
        for (; $list->idx < $list->count; ++$list->idx) {
            /**
             * Token parsed at this moment.
             *
             * @var Token $token
             */
            $token = $list->tokens[$list->idx];
            // End of statement.
            if ($token->type === Token::TYPE_DELIMITER) {
                break;
            }
            // Skipping whitespaces and comments.
            if ($token->type === Token::TYPE_WHITESPACE || $token->type === Token::TYPE_COMMENT) {
                if ($isExpr) {
                    $ret->expr .= $token->token;
                }
                continue;
            }
            if ($token->type === Token::TYPE_KEYWORD) {
                if ($brackets > 0 && empty($ret->subquery) && !empty(Parser::$STATEMENT_PARSERS[$token->value])) {
                    // A `(` was previously found and this keyword is the
                    // beginning of a statement, so this is a subquery.
                    $ret->subquery = $token->value;
                } elseif ($token->flags & Token::FLAG_KEYWORD_FUNCTION && (empty($options['parseField']) && !$alias)) {
                    $isExpr = true;
                } elseif ($token->flags & Token::FLAG_KEYWORD_RESERVED && $brackets === 0) {
                    if (empty(self::$ALLOWED_KEYWORDS[$token->value])) {
                        // A reserved keyword that is not allowed in the
                        // expression was found so the expression must have
                        // ended and a new clause is starting.
                        break;
                    }
                    if ($token->value === 'AS') {
                        if (!empty($options['breakOnAlias'])) {
                            break;
                        }
                        if ($alias) {
                            $parser->error(__('An alias was expected.'), $token);
                            break;
                        }
                        $alias = true;
                        continue;
                    } elseif ($token->value === 'CASE') {
                        // For a use of CASE like
                        // 'SELECT a = CASE .... END, b=1, `id`, ... FROM ...'
                        $tempCaseExpr = CaseExpression::parse($parser, $list);
                        $ret->expr .= CaseExpression::build($tempCaseExpr);
                        $isExpr = true;
                        continue;
                    }
                    $isExpr = true;
                } elseif ($brackets === 0 && strlen($ret->expr) > 0 && !$alias) {
                    /* End of expression */
                    break;
                }
            }
            if ($token->type === Token::TYPE_NUMBER || $token->type === Token::TYPE_BOOL || $token->type === Token::TYPE_SYMBOL && $token->flags & Token::FLAG_SYMBOL_VARIABLE || $token->type === Token::TYPE_OPERATOR && $token->value !== '.') {
                if (!empty($options['parseField'])) {
                    break;
                }
                // Numbers, booleans and operators (except dot) are usually part
                // of expressions.
                $isExpr = true;
            }
            if ($token->type === Token::TYPE_OPERATOR) {
                if (!empty($options['breakOnParentheses']) && ($token->value === '(' || $token->value === ')')) {
                    // No brackets were expected.
                    break;
                }
                if ($token->value === '(') {
                    ++$brackets;
                    if (empty($ret->function) && $prev[1] !== null && ($prev[1]->type === Token::TYPE_NONE || $prev[1]->type === Token::TYPE_SYMBOL || $prev[1]->type === Token::TYPE_KEYWORD && $prev[1]->flags & Token::FLAG_KEYWORD_FUNCTION)) {
                        $ret->function = $prev[1]->value;
                    }
                } elseif ($token->value === ')' && $brackets == 0) {
                    // Not our bracket
                    break;
                } elseif ($token->value === ')') {
                    --$brackets;
                    if ($brackets === 0) {
                        if (!empty($options['parenthesesDelimited'])) {
                            // The current token is the last bracket, the next
                            // one will be outside the expression.
                            $ret->expr .= $token->token;
                            ++$list->idx;
                            break;
                        }
                    } elseif ($brackets < 0) {
                        // $parser->error(__('Unexpected closing bracket.'), $token);
                        // $brackets = 0;
                        break;
                    }
                } elseif ($token->value === ',') {
                    // Expressions are comma-delimited.
                    if ($brackets === 0) {
                        break;
                    }
                }
            }
            // Saving the previous tokens.
            $prev[0] = $prev[1];
            $prev[1] = $token;
            if ($alias) {
                // An alias is expected (the keyword `AS` was previously found).
                if (!empty($ret->alias)) {
                    $parser->error(__('An alias was previously found.'), $token);
                    break;
                }
                $ret->alias = $token->value;
                $alias = false;
            } elseif ($isExpr) {
                // Handling aliases.
                if ($brackets === 0 && ($prev[0] === null || ($prev[0]->type !== Token::TYPE_OPERATOR || $prev[0]->token === ')') && ($prev[0]->type !== Token::TYPE_KEYWORD || !($prev[0]->flags & Token::FLAG_KEYWORD_RESERVED))) && ($prev[1]->type === Token::TYPE_STRING || $prev[1]->type === Token::TYPE_SYMBOL && !($prev[1]->flags & Token::FLAG_SYMBOL_VARIABLE) || $prev[1]->type === Token::TYPE_NONE)) {
                    if (!empty($ret->alias)) {
                        $parser->error(__('An alias was previously found.'), $token);
                        break;
                    }
                    $ret->alias = $prev[1]->value;
                } else {
                    $ret->expr .= $token->token;
                }
            } elseif (!$isExpr) {
                if ($token->type === Token::TYPE_OPERATOR && $token->value === '.') {
                    // Found a `.` which means we expect a column name and
                    // the column name we parsed is actually the table name
                    // and the table name is actually a database name.
                    if (!empty($ret->database) || $dot) {
                        $parser->error(__('Unexpected dot.'), $token);
                    }
                    $ret->database = $ret->table;
                    $ret->table = $ret->column;
                    $ret->column = null;
                    $dot = true;
                    $ret->expr .= $token->token;
                } else {
                    $field = empty($options['field']) ? 'column' : $options['field'];
                    if (empty($ret->{$field})) {
                        $ret->{$field} = $token->value;
                        $ret->expr .= $token->token;
                        $dot = false;
                    } else {
                        // No alias is expected.
                        if (!empty($options['breakOnAlias'])) {
                            break;
                        }
                        if (!empty($ret->alias)) {
                            $parser->error(__('An alias was previously found.'), $token);
                            break;
                        }
                        $ret->alias = $token->value;
                    }
                }
            }
        }
        if ($alias) {
            $parser->error(__('An alias was expected.'), $list->tokens[$list->idx - 1]);
        }
        // White-spaces might be added at the end.
        $ret->expr = trim($ret->expr);
        if ($ret->expr === '') {
            return null;
        }
        --$list->idx;
        return $ret;
    }

Usage Example

 /**
  * @param Parser     $parser  The parser that serves as context.
  * @param TokensList $list    The list of tokens that are being parsed.
  * @param array      $options Parameters for parsing.
  *
  * @return Expression[]
  */
 public static function parse(Parser $parser, TokensList $list, array $options = array())
 {
     $ret = array();
     /**
      * The state of the parser.
      *
      * Below are the states of the parser.
      *
      *      0 ----------------------[ array ]---------------------> 1
      *
      *      1 ------------------------[ , ]------------------------> 0
      *      1 -----------------------[ else ]----------------------> (END)
      *
      * @var int $state
      */
     $state = 0;
     for (; $list->idx < $list->count; ++$list->idx) {
         /**
          * Token parsed at this moment.
          *
          * @var Token $token
          */
         $token = $list->tokens[$list->idx];
         // End of statement.
         if ($token->type === Token::TYPE_DELIMITER) {
             break;
         }
         // Skipping whitespaces and comments.
         if ($token->type === Token::TYPE_WHITESPACE || $token->type === Token::TYPE_COMMENT) {
             continue;
         }
         if ($token->type === Token::TYPE_KEYWORD && $token->flags & Token::FLAG_KEYWORD_RESERVED && ~$token->flags & Token::FLAG_KEYWORD_FUNCTION && $token->value !== 'DUAL' && $token->value !== 'NULL' && $token->value !== 'CASE') {
             // No keyword is expected.
             break;
         }
         if ($state === 0) {
             if ($token->type === Token::TYPE_KEYWORD && $token->value === 'CASE') {
                 $expr = CaseExpression::parse($parser, $list, $options);
             } else {
                 $expr = Expression::parse($parser, $list, $options);
             }
             if ($expr === null) {
                 break;
             }
             $ret[] = $expr;
             $state = 1;
         } elseif ($state === 1) {
             if ($token->value === ',') {
                 $state = 0;
             } else {
                 break;
             }
         }
     }
     if ($state === 0) {
         $parser->error(__('An expression was expected.'), $list->tokens[$list->idx]);
     }
     --$list->idx;
     return $ret;
 }
All Usage Examples Of SqlParser\Components\Expression::parse