PHPCSHelper.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. <?php
  2. /**
  3. * PHPCompatibility, an external standard for PHP_CodeSniffer.
  4. *
  5. * @package PHPCompatibility
  6. * @copyright 2012-2019 PHPCompatibility Contributors
  7. * @license https://opensource.org/licenses/LGPL-3.0 LGPL3
  8. * @link https://github.com/PHPCompatibility/PHPCompatibility
  9. */
  10. namespace PHPCompatibility;
  11. use PHP_CodeSniffer_Exception as PHPCS_Exception;
  12. use PHP_CodeSniffer_File as File;
  13. use PHP_CodeSniffer_Tokens as Tokens;
  14. /**
  15. * PHPCS cross-version compatibility helper class.
  16. *
  17. * A number of PHPCS classes were split up into several classes in PHPCS 3.x
  18. * Those classes cannot be aliased as they don't represent the same object.
  19. * This class provides helper methods for functions which were contained in
  20. * one of these classes and which are used within the PHPCompatibility library.
  21. *
  22. * Additionally, this class contains some duplicates of PHPCS native methods.
  23. * These methods have received bug fixes or improved functionality between the
  24. * lowest supported PHPCS version and the latest PHPCS stable version and
  25. * to provide the same results cross-version, PHPCompatibility needs to use
  26. * the up-to-date versions of these methods.
  27. *
  28. * @since 8.0.0
  29. * @since 8.2.0 The duplicate PHPCS methods have been moved from the `Sniff`
  30. * base class to this class.
  31. */
  32. class PHPCSHelper
  33. {
  34. /**
  35. * Get the PHPCS version number.
  36. *
  37. * @since 8.0.0
  38. *
  39. * @return string
  40. */
  41. public static function getVersion()
  42. {
  43. if (\defined('\PHP_CodeSniffer\Config::VERSION')) {
  44. // PHPCS 3.x.
  45. return \PHP_CodeSniffer\Config::VERSION;
  46. } else {
  47. // PHPCS 2.x.
  48. return \PHP_CodeSniffer::VERSION;
  49. }
  50. }
  51. /**
  52. * Pass config data to PHPCS.
  53. *
  54. * PHPCS cross-version compatibility helper.
  55. *
  56. * @since 8.0.0
  57. *
  58. * @param string $key The name of the config value.
  59. * @param string|null $value The value to set. If null, the config entry
  60. * is deleted, reverting it to the default value.
  61. * @param boolean $temp Set this config data temporarily for this script run.
  62. * This will not write the config data to the config file.
  63. *
  64. * @return void
  65. */
  66. public static function setConfigData($key, $value, $temp = false)
  67. {
  68. if (method_exists('\PHP_CodeSniffer\Config', 'setConfigData')) {
  69. // PHPCS 3.x.
  70. \PHP_CodeSniffer\Config::setConfigData($key, $value, $temp);
  71. } else {
  72. // PHPCS 2.x.
  73. \PHP_CodeSniffer::setConfigData($key, $value, $temp);
  74. }
  75. }
  76. /**
  77. * Get the value of a single PHPCS config key.
  78. *
  79. * @since 8.0.0
  80. *
  81. * @param string $key The name of the config value.
  82. *
  83. * @return string|null
  84. */
  85. public static function getConfigData($key)
  86. {
  87. if (method_exists('\PHP_CodeSniffer\Config', 'getConfigData')) {
  88. // PHPCS 3.x.
  89. return \PHP_CodeSniffer\Config::getConfigData($key);
  90. } else {
  91. // PHPCS 2.x.
  92. return \PHP_CodeSniffer::getConfigData($key);
  93. }
  94. }
  95. /**
  96. * Get the value of a single PHPCS config key.
  97. *
  98. * This config key can be set in the `CodeSniffer.conf` file, on the
  99. * command-line or in a ruleset.
  100. *
  101. * @since 8.2.0
  102. *
  103. * @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
  104. * @param string $key The name of the config value.
  105. *
  106. * @return string|null
  107. */
  108. public static function getCommandLineData(File $phpcsFile, $key)
  109. {
  110. if (class_exists('\PHP_CodeSniffer\Config')) {
  111. // PHPCS 3.x.
  112. $config = $phpcsFile->config;
  113. if (isset($config->{$key})) {
  114. return $config->{$key};
  115. }
  116. } else {
  117. // PHPCS 2.x.
  118. $config = $phpcsFile->phpcs->cli->getCommandLineValues();
  119. if (isset($config[$key])) {
  120. return $config[$key];
  121. }
  122. }
  123. return null;
  124. }
  125. /**
  126. * Returns the position of the first non-whitespace token in a statement.
  127. *
  128. * {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File`
  129. * class and introduced in PHPCS 2.1.0 and improved in PHPCS 2.7.1.
  130. *
  131. * Once the minimum supported PHPCS version for this standard goes beyond
  132. * that, this method can be removed and calls to it replaced with
  133. * `$phpcsFile->findStartOfStatement($start, $ignore)` calls.
  134. *
  135. * Last synced with PHPCS version: PHPCS 3.3.2 at commit 6ad28354c04b364c3c71a34e4a18b629cc3b231e}
  136. *
  137. * @since 9.1.0
  138. *
  139. * @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile.
  140. * @param int $start The position to start searching from in the token stack.
  141. * @param int|array $ignore Token types that should not be considered stop points.
  142. *
  143. * @return int
  144. */
  145. public static function findStartOfStatement(File $phpcsFile, $start, $ignore = null)
  146. {
  147. if (version_compare(self::getVersion(), '2.7.1', '>=') === true) {
  148. return $phpcsFile->findStartOfStatement($start, $ignore);
  149. }
  150. $tokens = $phpcsFile->getTokens();
  151. $endTokens = Tokens::$blockOpeners;
  152. $endTokens[\T_COLON] = true;
  153. $endTokens[\T_COMMA] = true;
  154. $endTokens[\T_DOUBLE_ARROW] = true;
  155. $endTokens[\T_SEMICOLON] = true;
  156. $endTokens[\T_OPEN_TAG] = true;
  157. $endTokens[\T_CLOSE_TAG] = true;
  158. $endTokens[\T_OPEN_SHORT_ARRAY] = true;
  159. if ($ignore !== null) {
  160. $ignore = (array) $ignore;
  161. foreach ($ignore as $code) {
  162. if (isset($endTokens[$code]) === true) {
  163. unset($endTokens[$code]);
  164. }
  165. }
  166. }
  167. $lastNotEmpty = $start;
  168. for ($i = $start; $i >= 0; $i--) {
  169. if (isset($endTokens[$tokens[$i]['code']]) === true) {
  170. // Found the end of the previous statement.
  171. return $lastNotEmpty;
  172. }
  173. if (isset($tokens[$i]['scope_opener']) === true
  174. && $i === $tokens[$i]['scope_closer']
  175. ) {
  176. // Found the end of the previous scope block.
  177. return $lastNotEmpty;
  178. }
  179. // Skip nested statements.
  180. if (isset($tokens[$i]['bracket_opener']) === true
  181. && $i === $tokens[$i]['bracket_closer']
  182. ) {
  183. $i = $tokens[$i]['bracket_opener'];
  184. } elseif (isset($tokens[$i]['parenthesis_opener']) === true
  185. && $i === $tokens[$i]['parenthesis_closer']
  186. ) {
  187. $i = $tokens[$i]['parenthesis_opener'];
  188. }
  189. if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === false) {
  190. $lastNotEmpty = $i;
  191. }
  192. }//end for
  193. return 0;
  194. }
  195. /**
  196. * Returns the position of the last non-whitespace token in a statement.
  197. *
  198. * {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File`
  199. * class and introduced in PHPCS 2.1.0 and improved in PHPCS 2.7.1 and 3.3.0.
  200. *
  201. * Once the minimum supported PHPCS version for this standard goes beyond
  202. * that, this method can be removed and calls to it replaced with
  203. * `$phpcsFile->findEndOfStatement($start, $ignore)` calls.
  204. *
  205. * Last synced with PHPCS version: PHPCS 3.3.0-alpha at commit f5d899dcb5c534a1c3cca34668624517856ba823}
  206. *
  207. * @since 8.2.0
  208. *
  209. * @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile.
  210. * @param int $start The position to start searching from in the token stack.
  211. * @param int|array $ignore Token types that should not be considered stop points.
  212. *
  213. * @return int
  214. */
  215. public static function findEndOfStatement(File $phpcsFile, $start, $ignore = null)
  216. {
  217. if (version_compare(self::getVersion(), '3.3.0', '>=') === true) {
  218. return $phpcsFile->findEndOfStatement($start, $ignore);
  219. }
  220. $tokens = $phpcsFile->getTokens();
  221. $endTokens = array(
  222. \T_COLON => true,
  223. \T_COMMA => true,
  224. \T_DOUBLE_ARROW => true,
  225. \T_SEMICOLON => true,
  226. \T_CLOSE_PARENTHESIS => true,
  227. \T_CLOSE_SQUARE_BRACKET => true,
  228. \T_CLOSE_CURLY_BRACKET => true,
  229. \T_CLOSE_SHORT_ARRAY => true,
  230. \T_OPEN_TAG => true,
  231. \T_CLOSE_TAG => true,
  232. );
  233. if ($ignore !== null) {
  234. $ignore = (array) $ignore;
  235. foreach ($ignore as $code) {
  236. if (isset($endTokens[$code]) === true) {
  237. unset($endTokens[$code]);
  238. }
  239. }
  240. }
  241. $lastNotEmpty = $start;
  242. for ($i = $start; $i < $phpcsFile->numTokens; $i++) {
  243. if ($i !== $start && isset($endTokens[$tokens[$i]['code']]) === true) {
  244. // Found the end of the statement.
  245. if ($tokens[$i]['code'] === \T_CLOSE_PARENTHESIS
  246. || $tokens[$i]['code'] === \T_CLOSE_SQUARE_BRACKET
  247. || $tokens[$i]['code'] === \T_CLOSE_CURLY_BRACKET
  248. || $tokens[$i]['code'] === \T_CLOSE_SHORT_ARRAY
  249. || $tokens[$i]['code'] === \T_OPEN_TAG
  250. || $tokens[$i]['code'] === \T_CLOSE_TAG
  251. ) {
  252. return $lastNotEmpty;
  253. }
  254. return $i;
  255. }
  256. // Skip nested statements.
  257. if (isset($tokens[$i]['scope_closer']) === true
  258. && ($i === $tokens[$i]['scope_opener']
  259. || $i === $tokens[$i]['scope_condition'])
  260. ) {
  261. if ($i === $start && isset(Tokens::$scopeOpeners[$tokens[$i]['code']]) === true) {
  262. return $tokens[$i]['scope_closer'];
  263. }
  264. $i = $tokens[$i]['scope_closer'];
  265. } elseif (isset($tokens[$i]['bracket_closer']) === true
  266. && $i === $tokens[$i]['bracket_opener']
  267. ) {
  268. $i = $tokens[$i]['bracket_closer'];
  269. } elseif (isset($tokens[$i]['parenthesis_closer']) === true
  270. && $i === $tokens[$i]['parenthesis_opener']
  271. ) {
  272. $i = $tokens[$i]['parenthesis_closer'];
  273. }
  274. if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === false) {
  275. $lastNotEmpty = $i;
  276. }
  277. }//end for
  278. return ($phpcsFile->numTokens - 1);
  279. }
  280. /**
  281. * Returns the name of the class that the specified class extends
  282. * (works for classes, anonymous classes and interfaces).
  283. *
  284. * Returns FALSE on error or if there is no extended class name.
  285. *
  286. * {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File`
  287. * class, but with some improvements which have been introduced in
  288. * PHPCS 2.8.0.
  289. * {@link https://github.com/squizlabs/PHP_CodeSniffer/commit/0011d448119d4c568e3ac1f825ae78815bf2cc34}.
  290. *
  291. * Once the minimum supported PHPCS version for this standard goes beyond
  292. * that, this method can be removed and calls to it replaced with
  293. * `$phpcsFile->findExtendedClassName($stackPtr)` calls.
  294. *
  295. * Last synced with PHPCS version: PHPCS 3.1.0-alpha at commit a9efcc9b0703f3f9f4a900623d4e97128a6aafc6}
  296. *
  297. * @since 7.1.4
  298. * @since 8.2.0 Moved from the `Sniff` class to this class.
  299. *
  300. * @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile.
  301. * @param int $stackPtr The position of the class token in the stack.
  302. *
  303. * @return string|false
  304. */
  305. public static function findExtendedClassName(File $phpcsFile, $stackPtr)
  306. {
  307. if (version_compare(self::getVersion(), '3.1.0', '>=') === true) {
  308. return $phpcsFile->findExtendedClassName($stackPtr);
  309. }
  310. $tokens = $phpcsFile->getTokens();
  311. // Check for the existence of the token.
  312. if (isset($tokens[$stackPtr]) === false) {
  313. return false;
  314. }
  315. if ($tokens[$stackPtr]['code'] !== \T_CLASS
  316. && $tokens[$stackPtr]['type'] !== 'T_ANON_CLASS'
  317. && $tokens[$stackPtr]['type'] !== 'T_INTERFACE'
  318. ) {
  319. return false;
  320. }
  321. if (isset($tokens[$stackPtr]['scope_closer']) === false) {
  322. return false;
  323. }
  324. $classCloserIndex = $tokens[$stackPtr]['scope_closer'];
  325. $extendsIndex = $phpcsFile->findNext(\T_EXTENDS, $stackPtr, $classCloserIndex);
  326. if ($extendsIndex === false) {
  327. return false;
  328. }
  329. $find = array(
  330. \T_NS_SEPARATOR,
  331. \T_STRING,
  332. \T_WHITESPACE,
  333. );
  334. $end = $phpcsFile->findNext($find, ($extendsIndex + 1), $classCloserIndex, true);
  335. $name = $phpcsFile->getTokensAsString(($extendsIndex + 1), ($end - $extendsIndex - 1));
  336. $name = trim($name);
  337. if ($name === '') {
  338. return false;
  339. }
  340. return $name;
  341. }
  342. /**
  343. * Returns the name(s) of the interface(s) that the specified class implements.
  344. *
  345. * Returns FALSE on error or if there are no implemented interface names.
  346. *
  347. * {@internal Duplicate of same method as introduced in PHPCS 2.7.
  348. * This method also includes an improvement we use which was only introduced
  349. * in PHPCS 2.8.0, so only defer to upstream for higher versions.
  350. * Once the minimum supported PHPCS version for this sniff library goes beyond
  351. * that, this method can be removed and calls to it replaced with
  352. * `$phpcsFile->findImplementedInterfaceNames($stackPtr)` calls.}
  353. *
  354. * @since 7.0.3
  355. * @since 8.2.0 Moved from the `Sniff` class to this class.
  356. *
  357. * @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
  358. * @param int $stackPtr The position of the class token.
  359. *
  360. * @return array|false
  361. */
  362. public static function findImplementedInterfaceNames(File $phpcsFile, $stackPtr)
  363. {
  364. if (version_compare(self::getVersion(), '2.7.1', '>') === true) {
  365. return $phpcsFile->findImplementedInterfaceNames($stackPtr);
  366. }
  367. $tokens = $phpcsFile->getTokens();
  368. // Check for the existence of the token.
  369. if (isset($tokens[$stackPtr]) === false) {
  370. return false;
  371. }
  372. if ($tokens[$stackPtr]['code'] !== \T_CLASS
  373. && $tokens[$stackPtr]['type'] !== 'T_ANON_CLASS'
  374. ) {
  375. return false;
  376. }
  377. if (isset($tokens[$stackPtr]['scope_closer']) === false) {
  378. return false;
  379. }
  380. $classOpenerIndex = $tokens[$stackPtr]['scope_opener'];
  381. $implementsIndex = $phpcsFile->findNext(\T_IMPLEMENTS, $stackPtr, $classOpenerIndex);
  382. if ($implementsIndex === false) {
  383. return false;
  384. }
  385. $find = array(
  386. \T_NS_SEPARATOR,
  387. \T_STRING,
  388. \T_WHITESPACE,
  389. \T_COMMA,
  390. );
  391. $end = $phpcsFile->findNext($find, ($implementsIndex + 1), ($classOpenerIndex + 1), true);
  392. $name = $phpcsFile->getTokensAsString(($implementsIndex + 1), ($end - $implementsIndex - 1));
  393. $name = trim($name);
  394. if ($name === '') {
  395. return false;
  396. } else {
  397. $names = explode(',', $name);
  398. $names = array_map('trim', $names);
  399. return $names;
  400. }
  401. }
  402. /**
  403. * Returns the method parameters for the specified function token.
  404. *
  405. * Each parameter is in the following format:
  406. *
  407. * <code>
  408. * 0 => array(
  409. * 'name' => '$var', // The variable name.
  410. * 'token' => integer, // The stack pointer to the variable name.
  411. * 'content' => string, // The full content of the variable definition.
  412. * 'pass_by_reference' => boolean, // Is the variable passed by reference?
  413. * 'variable_length' => boolean, // Is the param of variable length through use of `...` ?
  414. * 'type_hint' => string, // The type hint for the variable.
  415. * 'type_hint_token' => integer, // The stack pointer to the type hint
  416. * // or false if there is no type hint.
  417. * 'nullable_type' => boolean, // Is the variable using a nullable type?
  418. * )
  419. * </code>
  420. *
  421. * Parameters with default values have an additional array index of
  422. * 'default' with the value of the default as a string.
  423. *
  424. * {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File`
  425. * class.
  426. *
  427. * Last synced with PHPCS version: PHPCS 3.3.0-alpha at commit 53a28408d345044c0360c2c1b4a2aaebf4a3b8c9}
  428. *
  429. * @since 7.0.3
  430. * @since 8.2.0 Moved from the `Sniff` class to this class.
  431. *
  432. * @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile.
  433. * @param int $stackPtr The position in the stack of the
  434. * function token to acquire the
  435. * parameters for.
  436. *
  437. * @return array|false
  438. * @throws \PHP_CodeSniffer_Exception If the specified $stackPtr is not of
  439. * type T_FUNCTION or T_CLOSURE.
  440. */
  441. public static function getMethodParameters(File $phpcsFile, $stackPtr)
  442. {
  443. if (version_compare(self::getVersion(), '3.3.0', '>=') === true) {
  444. return $phpcsFile->getMethodParameters($stackPtr);
  445. }
  446. $tokens = $phpcsFile->getTokens();
  447. // Check for the existence of the token.
  448. if (isset($tokens[$stackPtr]) === false) {
  449. return false;
  450. }
  451. if ($tokens[$stackPtr]['code'] !== \T_FUNCTION
  452. && $tokens[$stackPtr]['code'] !== \T_CLOSURE
  453. ) {
  454. throw new PHPCS_Exception('$stackPtr must be of type T_FUNCTION or T_CLOSURE');
  455. }
  456. $opener = $tokens[$stackPtr]['parenthesis_opener'];
  457. $closer = $tokens[$stackPtr]['parenthesis_closer'];
  458. $vars = array();
  459. $currVar = null;
  460. $paramStart = ($opener + 1);
  461. $defaultStart = null;
  462. $paramCount = 0;
  463. $passByReference = false;
  464. $variableLength = false;
  465. $typeHint = '';
  466. $typeHintToken = false;
  467. $nullableType = false;
  468. for ($i = $paramStart; $i <= $closer; $i++) {
  469. // Check to see if this token has a parenthesis or bracket opener. If it does
  470. // it's likely to be an array which might have arguments in it. This
  471. // could cause problems in our parsing below, so lets just skip to the
  472. // end of it.
  473. if (isset($tokens[$i]['parenthesis_opener']) === true) {
  474. // Don't do this if it's the close parenthesis for the method.
  475. if ($i !== $tokens[$i]['parenthesis_closer']) {
  476. $i = ($tokens[$i]['parenthesis_closer'] + 1);
  477. }
  478. }
  479. if (isset($tokens[$i]['bracket_opener']) === true) {
  480. // Don't do this if it's the close parenthesis for the method.
  481. if ($i !== $tokens[$i]['bracket_closer']) {
  482. $i = ($tokens[$i]['bracket_closer'] + 1);
  483. }
  484. }
  485. switch ($tokens[$i]['type']) {
  486. case 'T_BITWISE_AND':
  487. if ($defaultStart === null) {
  488. $passByReference = true;
  489. }
  490. break;
  491. case 'T_VARIABLE':
  492. $currVar = $i;
  493. break;
  494. case 'T_ELLIPSIS':
  495. $variableLength = true;
  496. break;
  497. case 'T_ARRAY_HINT': // Pre-PHPCS 3.3.0.
  498. case 'T_CALLABLE':
  499. if ($typeHintToken === false) {
  500. $typeHintToken = $i;
  501. }
  502. $typeHint .= $tokens[$i]['content'];
  503. break;
  504. case 'T_SELF':
  505. case 'T_PARENT':
  506. case 'T_STATIC':
  507. // Self and parent are valid, static invalid, but was probably intended as type hint.
  508. if (isset($defaultStart) === false) {
  509. if ($typeHintToken === false) {
  510. $typeHintToken = $i;
  511. }
  512. $typeHint .= $tokens[$i]['content'];
  513. }
  514. break;
  515. case 'T_STRING':
  516. // This is a string, so it may be a type hint, but it could
  517. // also be a constant used as a default value.
  518. $prevComma = false;
  519. for ($t = $i; $t >= $opener; $t--) {
  520. if ($tokens[$t]['code'] === \T_COMMA) {
  521. $prevComma = $t;
  522. break;
  523. }
  524. }
  525. if ($prevComma !== false) {
  526. $nextEquals = false;
  527. for ($t = $prevComma; $t < $i; $t++) {
  528. if ($tokens[$t]['code'] === \T_EQUAL) {
  529. $nextEquals = $t;
  530. break;
  531. }
  532. }
  533. if ($nextEquals !== false) {
  534. break;
  535. }
  536. }
  537. if ($defaultStart === null) {
  538. if ($typeHintToken === false) {
  539. $typeHintToken = $i;
  540. }
  541. $typeHint .= $tokens[$i]['content'];
  542. }
  543. break;
  544. case 'T_NS_SEPARATOR':
  545. // Part of a type hint or default value.
  546. if ($defaultStart === null) {
  547. if ($typeHintToken === false) {
  548. $typeHintToken = $i;
  549. }
  550. $typeHint .= $tokens[$i]['content'];
  551. }
  552. break;
  553. case 'T_NULLABLE':
  554. case 'T_INLINE_THEN': // Pre-PHPCS 2.8.0.
  555. if ($defaultStart === null) {
  556. $nullableType = true;
  557. $typeHint .= $tokens[$i]['content'];
  558. }
  559. break;
  560. case 'T_CLOSE_PARENTHESIS':
  561. case 'T_COMMA':
  562. // If it's null, then there must be no parameters for this
  563. // method.
  564. if ($currVar === null) {
  565. break;
  566. }
  567. $vars[$paramCount] = array();
  568. $vars[$paramCount]['token'] = $currVar;
  569. $vars[$paramCount]['name'] = $tokens[$currVar]['content'];
  570. $vars[$paramCount]['content'] = trim($phpcsFile->getTokensAsString($paramStart, ($i - $paramStart)));
  571. if ($defaultStart !== null) {
  572. $vars[$paramCount]['default'] = trim(
  573. $phpcsFile->getTokensAsString(
  574. $defaultStart,
  575. ($i - $defaultStart)
  576. )
  577. );
  578. }
  579. $vars[$paramCount]['pass_by_reference'] = $passByReference;
  580. $vars[$paramCount]['variable_length'] = $variableLength;
  581. $vars[$paramCount]['type_hint'] = $typeHint;
  582. $vars[$paramCount]['type_hint_token'] = $typeHintToken;
  583. $vars[$paramCount]['nullable_type'] = $nullableType;
  584. // Reset the vars, as we are about to process the next parameter.
  585. $defaultStart = null;
  586. $paramStart = ($i + 1);
  587. $passByReference = false;
  588. $variableLength = false;
  589. $typeHint = '';
  590. $typeHintToken = false;
  591. $nullableType = false;
  592. $paramCount++;
  593. break;
  594. case 'T_EQUAL':
  595. $defaultStart = ($i + 1);
  596. break;
  597. }//end switch
  598. }//end for
  599. return $vars;
  600. }
  601. }