Seditio Source
Root |
./othercms/phpBB3/vendor/zendframework/zend-code/src/Scanner/MethodScanner.php
<?php
/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
 * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
 * @license   http://framework.zend.com/license/new-bsd New BSD License
 */

namespace Zend\Code\Scanner;

use
Zend\Code\Annotation\AnnotationManager;
use
Zend\Code\Exception;
use
Zend\Code\NameInformation;

use function
array_slice;
use function
count;
use function
is_int;
use function
is_string;
use function
ltrim;
use function
strtolower;
use function
substr_count;
use function
var_export;

class
MethodScanner implements ScannerInterface
{
   
/**
     * @var bool
     */
   
protected $isScanned = false;

   
/**
     * @var string
     */
   
protected $docComment;

   
/**
     * @var ClassScanner
     */
   
protected $scannerClass;

   
/**
     * @var string
     */
   
protected $class;

   
/**
     * @var string
     */
   
protected $name;

   
/**
     * @var int
     */
   
protected $lineStart;

   
/**
     * @var int
     */
   
protected $lineEnd;

   
/**
     * @var bool
     */
   
protected $isFinal = false;

   
/**
     * @var bool
     */
   
protected $isAbstract = false;

   
/**
     * @var bool
     */
   
protected $isPublic = true;

   
/**
     * @var bool
     */
   
protected $isProtected = false;

   
/**
     * @var bool
     */
   
protected $isPrivate = false;

   
/**
     * @var bool
     */
   
protected $isStatic = false;

   
/**
     * @var string
     */
   
protected $body = '';

   
/**
     * @var array
     */
   
protected $tokens = [];

   
/**
     * @var NameInformation
     */
   
protected $nameInformation;

   
/**
     * @var array
     */
   
protected $infos = [];

   
/**
     * @param  array $methodTokens
     * @param NameInformation $nameInformation
     */
   
public function __construct(array $methodTokens, NameInformation $nameInformation = null)
    {
       
$this->tokens          = $methodTokens;
       
$this->nameInformation = $nameInformation;
    }

   
/**
     * @param  string $class
     * @return MethodScanner
     */
   
public function setClass($class)
    {
       
$this->class = (string) $class;
        return
$this;
    }

   
/**
     * @param  ClassScanner  $scannerClass
     * @return MethodScanner
     */
   
public function setScannerClass(ClassScanner $scannerClass)
    {
       
$this->scannerClass = $scannerClass;
        return
$this;
    }

   
/**
     * @return ClassScanner
     */
   
public function getClassScanner()
    {
        return
$this->scannerClass;
    }

   
/**
     * @return string
     */
   
public function getName()
    {
       
$this->scan();

        return
$this->name;
    }

   
/**
     * @return int
     */
   
public function getLineStart()
    {
       
$this->scan();

        return
$this->lineStart;
    }

   
/**
     * @return int
     */
   
public function getLineEnd()
    {
       
$this->scan();

        return
$this->lineEnd;
    }

   
/**
     * @return string
     */
   
public function getDocComment()
    {
       
$this->scan();

        return
$this->docComment;
    }

   
/**
     * @param  AnnotationManager $annotationManager
     * @return AnnotationScanner|false
     */
   
public function getAnnotations(AnnotationManager $annotationManager)
    {
        if ((
$docComment = $this->getDocComment()) == '') {
            return
false;
        }

        return new
AnnotationScanner($annotationManager, $docComment, $this->nameInformation);
    }

   
/**
     * @return bool
     */
   
public function isFinal()
    {
       
$this->scan();

        return
$this->isFinal;
    }

   
/**
     * @return bool
     */
   
public function isAbstract()
    {
       
$this->scan();

        return
$this->isAbstract;
    }

   
/**
     * @return bool
     */
   
public function isPublic()
    {
       
$this->scan();

        return
$this->isPublic;
    }

   
/**
     * @return bool
     */
   
public function isProtected()
    {
       
$this->scan();

        return
$this->isProtected;
    }

   
/**
     * @return bool
     */
   
public function isPrivate()
    {
       
$this->scan();

        return
$this->isPrivate;
    }

   
/**
     * @return bool
     */
   
public function isStatic()
    {
       
$this->scan();

        return
$this->isStatic;
    }

   
/**
     * Override the given name for a method, this is necessary to
     * support traits.
     *
     * @param string $name
     * @return self
     */
   
public function setName($name)
    {
       
$this->name = $name;
        return
$this;
    }

   
/**
     * Visibility must be of T_PUBLIC, T_PRIVATE or T_PROTECTED
     * Needed to support traits
     *
     * @param int $visibility   T_PUBLIC | T_PRIVATE | T_PROTECTED
     * @return self
     * @throws \Zend\Code\Exception\InvalidArgumentException
     */
   
public function setVisibility($visibility)
    {
        switch (
$visibility) {
            case
T_PUBLIC:
               
$this->isPublic = true;
               
$this->isPrivate = false;
               
$this->isProtected = false;
                break;

            case
T_PRIVATE:
               
$this->isPublic = false;
               
$this->isPrivate = true;
               
$this->isProtected = false;
                break;

            case
T_PROTECTED:
               
$this->isPublic = false;
               
$this->isPrivate = false;
               
$this->isProtected = true;
                break;

            default:
                throw new
Exception\InvalidArgumentException('Invalid visibility argument passed to setVisibility.');
        }

        return
$this;
    }

   
/**
     * @return int
     */
   
public function getNumberOfParameters()
    {
        return
count($this->getParameters());
    }

   
/**
     * @param  bool $returnScanner
     * @return array
     */
   
public function getParameters($returnScanner = false)
    {
       
$this->scan();

       
$return = [];

        foreach (
$this->infos as $info) {
            if (
$info['type'] != 'parameter') {
                continue;
            }

            if (!
$returnScanner) {
               
$return[] = $info['name'];
            } else {
               
$return[] = $this->getParameter($info['name']);
            }
        }

        return
$return;
    }

   
/**
     * @param  int|string $parameterNameOrInfoIndex
     * @return ParameterScanner
     * @throws Exception\InvalidArgumentException
     */
   
public function getParameter($parameterNameOrInfoIndex)
    {
       
$this->scan();

        if (
is_int($parameterNameOrInfoIndex)) {
           
$info = $this->infos[$parameterNameOrInfoIndex];
            if (
$info['type'] != 'parameter') {
                throw new
Exception\InvalidArgumentException('Index of info offset is not about a parameter');
            }
        } elseif (
is_string($parameterNameOrInfoIndex)) {
            foreach (
$this->infos as $info) {
                if (
$info['type'] === 'parameter' && $info['name'] === $parameterNameOrInfoIndex) {
                    break;
                }
                unset(
$info);
            }
            if (! isset(
$info)) {
                throw new
Exception\InvalidArgumentException('Index of info offset is not about a parameter');
            }
        }

       
$p = new ParameterScanner(
           
array_slice($this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart']),
           
$this->nameInformation
       
);
       
$p->setDeclaringFunction($this->name);
       
$p->setDeclaringScannerFunction($this);
       
$p->setDeclaringClass($this->class);
       
$p->setDeclaringScannerClass($this->scannerClass);
       
$p->setPosition($info['position']);

        return
$p;
    }

   
/**
     * @return string
     */
   
public function getBody()
    {
       
$this->scan();

        return
$this->body;
    }

    public static function
export()
    {
       
// @todo
   
}

    public function
__toString()
    {
       
$this->scan();

        return
var_export($this, true);
    }

    protected function
scan()
    {
        if (
$this->isScanned) {
            return;
        }

        if (!
$this->tokens) {
            throw new
Exception\RuntimeException('No tokens were provided');
        }

       
/**
         * Variables & Setup
         */
       
$tokens       = &$this->tokens; // localize
       
$infos        = &$this->infos; // localize
       
$tokenIndex   = null;
       
$token        = null;
       
$tokenType    = null;
       
$tokenContent = null;
       
$tokenLine    = null;
       
$infoIndex    = 0;
       
$parentCount  = 0;

       
/*
         * MACRO creation
         */
       
$MACRO_TOKEN_ADVANCE = function () use (
            &
$tokens,
            &
$tokenIndex,
            &
$token,
            &
$tokenType,
            &
$tokenContent,
            &
$tokenLine
       
) {
            static
$lastTokenArray = null;
           
$tokenIndex = $tokenIndex === null ? 0 : $tokenIndex + 1;
            if (! isset(
$tokens[$tokenIndex])) {
               
$token        = false;
               
$tokenContent = false;
               
$tokenType    = false;
               
$tokenLine    = false;

                return
false;
            }
           
$token = $tokens[$tokenIndex];
            if (
is_string($token)) {
               
$tokenType    = null;
               
$tokenContent = $token;
               
$tokenLine   += substr_count(
                   
$lastTokenArray[1] ?? '',
                   
"\n"
               
); // adjust token line by last known newline count
           
} else {
               
$lastTokenArray = $token;
                [
$tokenType, $tokenContent, $tokenLine] = $token;
            }

            return
$tokenIndex;
        };
       
$MACRO_INFO_START    = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
           
$infos[$infoIndex] = [
               
'type'        => 'parameter',
               
'tokenStart'  => $tokenIndex,
               
'tokenEnd'    => null,
               
'lineStart'   => $tokenLine,
               
'lineEnd'     => $tokenLine,
               
'name'        => null,
               
'position'    => $infoIndex + 1, // position is +1 of infoIndex
           
];
        };
       
$MACRO_INFO_ADVANCE  = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
           
$infos[$infoIndex]['tokenEnd'] = $tokenIndex;
           
$infos[$infoIndex]['lineEnd']  = $tokenLine;
           
$infoIndex++;

            return
$infoIndex;
        };

       
/**
         * START FINITE STATE MACHINE FOR SCANNING TOKENS
         */
        // Initialize token
       
$MACRO_TOKEN_ADVANCE();

       
SCANNER_TOP:

       
$this->lineStart = $this->lineStart ? : $tokenLine;

        switch (
$tokenType) {
            case
T_DOC_COMMENT:
               
$this->lineStart = null;
                if (
$this->docComment === null && $this->name === null) {
                   
$this->docComment = $tokenContent;
                }
                goto
SCANNER_CONTINUE_SIGNATURE;
               
// goto (no break needed);

           
case T_FINAL:
               
$this->isFinal = true;
                goto
SCANNER_CONTINUE_SIGNATURE;
               
// goto (no break needed);

           
case T_ABSTRACT:
               
$this->isAbstract = true;
                goto
SCANNER_CONTINUE_SIGNATURE;
               
// goto (no break needed);

           
case T_PUBLIC:
               
// use defaults
               
goto SCANNER_CONTINUE_SIGNATURE;
               
// goto (no break needed);

           
case T_PROTECTED:
               
$this->setVisibility(T_PROTECTED);
                goto
SCANNER_CONTINUE_SIGNATURE;
               
// goto (no break needed);

           
case T_PRIVATE:
               
$this->setVisibility(T_PRIVATE);
                goto
SCANNER_CONTINUE_SIGNATURE;
               
// goto (no break needed);

           
case T_STATIC:
               
$this->isStatic = true;
                goto
SCANNER_CONTINUE_SIGNATURE;
               
// goto (no break needed);

           
case T_NS_SEPARATOR:
                if (! isset(
$infos[$infoIndex])) {
                   
$MACRO_INFO_START();
                }
                goto
SCANNER_CONTINUE_SIGNATURE;
               
// goto (no break needed);

           
case T_VARIABLE:
            case
T_STRING:
                if (
$tokenType === T_STRING && $parentCount === 0) {
                   
$this->name = $tokenContent;
                }

                if (
$parentCount === 1) {
                    if (! isset(
$infos[$infoIndex])) {
                       
$MACRO_INFO_START();
                    }
                    if (
$tokenType === T_VARIABLE) {
                       
$infos[$infoIndex]['name'] = ltrim($tokenContent, '$');
                    }
                }

                goto
SCANNER_CONTINUE_SIGNATURE;
               
// goto (no break needed);

           
case null:
                switch (
$tokenContent) {
                    case
'&':
                        if (! isset(
$infos[$infoIndex])) {
                           
$MACRO_INFO_START();
                        }
                        goto
SCANNER_CONTINUE_SIGNATURE;
                       
// goto (no break needed);
                   
case '(':
                       
$parentCount++;
                        goto
SCANNER_CONTINUE_SIGNATURE;
                       
// goto (no break needed);
                   
case ')':
                       
$parentCount--;
                        if (
$parentCount > 0) {
                            goto
SCANNER_CONTINUE_SIGNATURE;
                        }
                        if (
$parentCount === 0) {
                            if (
$infos) {
                               
$MACRO_INFO_ADVANCE();
                            }
                           
$context = 'body';
                        }
                        goto
SCANNER_CONTINUE_BODY;
                       
// goto (no break needed);
                   
case ',':
                        if (
$parentCount === 1) {
                           
$MACRO_INFO_ADVANCE();
                        }
                        goto
SCANNER_CONTINUE_SIGNATURE;
                }
        }

       
SCANNER_CONTINUE_SIGNATURE:

        if (
$MACRO_TOKEN_ADVANCE() === false) {
            goto
SCANNER_END;
        }
        goto
SCANNER_TOP;

       
SCANNER_CONTINUE_BODY:

       
$braceCount = 0;
        while (
$MACRO_TOKEN_ADVANCE() !== false) {
            if (
$tokenContent == '}') {
               
$braceCount--;
            }
            if (
$braceCount > 0) {
               
$this->body .= $tokenContent;
            }
            if (
$tokenContent == '{') {
               
$braceCount++;
            }
           
$this->lineEnd = $tokenLine;
        }

       
SCANNER_END:

       
$this->isScanned = true;
    }
}