Completed
Push — master ( a6414e...a14e1b )
by Shcherbak
02:22
created

ParametersPattern::withoutArgument()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
cc 1
eloc 5
nc 1
nop 1
crap 1
1
<?php
2
3
  namespace Funivan\PhpTokenizer\Pattern\Patterns;
4
5
  use Funivan\PhpTokenizer\Collection;
6
  use Funivan\PhpTokenizer\QuerySequence\QuerySequence;
7
  use Funivan\PhpTokenizer\Strategy\Section;
8
  use Funivan\PhpTokenizer\Token;
9
10
  /**
11
   * Find method in code
12
   */
13
  class ParametersPattern implements PatternInterface {
14
15
    /**
16
     * @var array
17
     */
18
    private $argumentCheck = [];
19
20
    /**
21
     * @var int|null
22
     */
23
    private $outputArgument = null;
24
25
26
    /**
27
     *
28
     */
29 18
    public function __construct() {
30 14
      $this->outputFull();
31 18
    }
32
33
34
    /**
35
     * @param QuerySequence $querySequence
36
     * @return Collection|null
37
     * @throws \Exception
38
     */
39 17
    public function __invoke(QuerySequence $querySequence) {
40 14
      $querySequence->strict(T_FUNCTION);
41 14
      $querySequence->possible(T_WHITESPACE);
42 14
      $querySequence->possible(T_STRING);
43 14
      $querySequence->possible(T_WHITESPACE);
44
45 14
      $section = $querySequence->section('(', ')');
46 14
      if ($section->count() === 0) {
47 14
        return null;
48
      }
49
50 14
      $section->slice(1, -1);
51
52 17
      if (empty($this->argumentCheck) and $this->outputArgument === null) {
53 8
        return $section;
54
      }
55
56
57
      /** @var Collection[] $arguments */
58 12
      $arguments = $this->getArguments($section);
59
60 15
      foreach ($this->argumentCheck as $index => $check) {
61
62 9
        $argumentTokens = isset($arguments[$index]) ? $arguments[$index] : new Collection();;
63 8
        $result = $check($argumentTokens);
64
65 8
        if (!is_bool($result)) {
66 2
          throw new \Exception('Argument check function should return boolean');
67
        }
68
69 6
        if ($result === false) {
70 7
          return null;
71
        }
72 8
      }
73
74 13
      if ($this->outputArgument) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->outputArgument of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
75 6
        $argumentCollection = !empty($arguments[$this->outputArgument]) ? $arguments[$this->outputArgument] : null;
76
77 6
        return $argumentCollection;
78
      }
79
80
      # output full
81 7
      return $section;
82
    }
83
84
85
    /**
86
     * @param int $int
87
     * @param callable $check
88
     * @return $this
89
     */
90 10
    public function withArgument($int, callable $check = null) {
91 10
      if ($check === null) {
92
        $check = function (Collection $argumentTokens) {
93 4
          return $argumentTokens->count() !== 0;
94 4
        };
95 2
      }
96 10
      $this->argumentCheck[$int] = $check;
97 10
      return $this;
98 2
    }
99
100
101
    /**
102
     * @param int $int
103
     * @return $this
104
     */
105
    public function withoutArgument($int) {
106 2
      $check = function (Collection $argumentTokens) {
107 2
        return $argumentTokens->count() === 0;
108 2
      };
109
110 3
      $this->argumentCheck[$int] = $check;
111 3
      return $this;
112
    }
113
114
115
    /**
116
     * @param $section
117
     * @return array
118
     */
119 16
    protected function getArguments(Collection $section) {
120
      /** @var Token $skipToToken */
121 15
      $skipToToken = null;
122 15
      $argumentIndex = 1;
123 15
      $arguments = [];
124 12
      $tokensNum = ($section->count() - 1);
125 12
      for ($tokenIndex = 0; $tokenIndex <= $tokensNum; $tokenIndex++) {
126
127 12
        $token = $section->offsetGet($tokenIndex);
128
129 12
        if ($token === null) {
130
          return null;
131
        }
132
133 12
        if ($skipToToken === null or $token->getIndex() >= $skipToToken->getIndex()) {
134 12
          if ($token->getValue() === ',') {
135 16
            $argumentIndex++;
136 16
            continue;
137
          }
138 12
          $skipToToken = $this->getEndArray($token, $section, $tokenIndex);
139 6
        }
140
141
142 12
        if (!isset($arguments[$argumentIndex])) {
143 12
          $arguments[$argumentIndex] = new Collection();
144 6
        }
145 12
        $arguments[$argumentIndex][] = $token;
146 6
      }
147
148 15
      return $arguments;
149 3
    }
150
151
152
    /**
153
     * @param Token $token
154
     * @param Collection $section
155
     * @param $index
156
     * @return Token
157
     */
158 12
    private function getEndArray(Token $token, Collection $section, $index) {
159
      // # check if we have array start
160
161 12
      if ($token->getValue() === '[') {
162 10
        $result = (new Section())->setDelimiters('[', ']')->process($section, $index);
163 10
        return $result->getToken();
164
      }
165
166 12
      if ($token->getValue() === 'array') {
167
168
        # skip whitespace
169 2
        $nextIndex = ($index + 1);
170 2
        $nextToken = $section->offsetGet($nextIndex);
171 2
        if ($nextToken->getType() === T_WHITESPACE) {
172 2
          $nextIndex = ($index + 2);
173 1
        }
174
175 2
        $result = (new Section())->setDelimiters('(', ')')->process($section, $nextIndex);
176 2
        return $result->getToken();
177
      }
178
179 12
      return null;
180
    }
181
182
183
    /**
184
     * @return $this
185
     */
186 18
    public function outputFull() {
187 18
      $this->outputArgument = null;
188 18
      return $this;
189
    }
190
191
192
    /**
193
     * @param $int
194
     * @return $this
195
     */
196 6
    public function outputArgument($int) {
197 6
      $this->outputArgument = $int;
198 6
      return $this;
199
    }
200
201
  }