Skip to content

Instantly share code, notes, and snippets.

@Zeronights
Last active August 7, 2025 18:36
Show Gist options
  • Save Zeronights/7b7d90fcf8d4daf9db0c to your computer and use it in GitHub Desktop.
Save Zeronights/7b7d90fcf8d4daf9db0c to your computer and use it in GitHub Desktop.

Revisions

  1. Zeronights revised this gist May 19, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -60,5 +60,5 @@ I will eventually move this class to its own repository and add it to composer.
    $class->hasUseStatement('SomeNamespace\SomeClass'); // false

    ## Disclaimer
    This was created as a proof of concept to answer my own [StackOverflow question](http://stackoverflow.com/questions/30308137/get-use-statement-from-class). As such, there are no tests or more comprehensive documentation. I will refine and release this class as a fully tested package soon. In the meantime, please have a look and tell me what you think.
    This was created as a proof of concept to answer my own [StackOverflow question](http://stackoverflow.com/questions/30308137/get-use-statement-from-class). As such, there are no tests or more comprehensive documentation. I will refine and release this class as a fully tested package soon. There is much which can be improved, especially in the `tokenizeSource` method. In the meantime, please have a look and tell me what you think.

  2. Zeronights revised this gist May 19, 2015. 1 changed file with 0 additions and 0 deletions.
    Empty file removed ExtendedReflectionCalass.php
    Empty file.
  3. Zeronights revised this gist May 19, 2015. 1 changed file with 0 additions and 0 deletions.
    Empty file added ExtendedReflectionCalass.php
    Empty file.
  4. Zeronights created this gist May 19, 2015.
    238 changes: 238 additions & 0 deletions ExtendedReflectionClass.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,238 @@
    <?php

    /**
    * The MIT License (MIT)
    *
    * Copyright (c) Ozgur (Ozzy) Giritli <[email protected]>
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to deal
    * in the Software without restriction, including without limitation the rights
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    * copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in
    * all copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    * THE SOFTWARE.
    */
    class ExtendedReflectionClass extends ReflectionClass {


    /**
    * Array of use statements for class.
    *
    * @var array
    */
    protected $useStatements = [];


    /**
    * Check if use statements have been parsed.
    *
    * @var boolean
    */
    protected $useStatementsParsed = false;


    /**
    * Parse class file and get use statements from current namespace.
    *
    * @return void
    */
    protected function parseUseStatements() {

    if ($this->useStatementsParsed) {
    return $this->useStatements;
    }

    if (!$this->isUserDefined()) {
    throw new RuntimeException('Must parse use statements from user defined classes.');
    }

    $source = $this->readFileSource();
    $this->useStatements = $this->tokenizeSource($source);

    $this->useStatementsParsed = true;
    return $this->useStatements;
    }


    /**
    * Read file source up to the line where our class is defined.
    *
    * @return string
    */
    private function readFileSource() {

    $file = fopen($this->getFileName(), 'r');
    $line = 0;
    $source = '';

    while (!feof($file)) {
    ++$line;

    if ($line >= $this->getStartLine()) {
    break;
    }

    $source .= fgets($file);
    }

    fclose($file);

    return $source;
    }


    /**
    * Parse the use statements from read source by
    * tokenizing and reading the tokens. Returns
    * an array of use statements and aliases.
    *
    * @param string $source
    * @return array
    */
    private function tokenizeSource($source) {

    $tokens = token_get_all($source);

    $builtNamespace = '';
    $buildingNamespace = false;
    $matchedNamespace = false;

    $useStatements = [];
    $record = false;
    $currentUse = [
    'class' => '',
    'as' => ''
    ];

    foreach ($tokens as $token) {

    if ($token[0] === T_NAMESPACE) {
    $buildingNamespace = true;

    if ($matchedNamespace) {
    break;
    }
    }

    if ($buildingNamespace) {

    if ($token === ';') {
    $buildingNamespace = false;
    continue;
    }

    switch ($token[0]) {

    case T_STRING:
    case T_NS_SEPARATOR:
    $builtNamespace .= $token[1];
    break;
    }

    continue;
    }

    if ($token === ';' || !is_array($token)) {

    if ($record) {
    $useStatements[] = $currentUse;
    $record = false;
    $currentUse = [
    'class' => '',
    'as' => ''
    ];
    }

    continue;
    }

    if ($token[0] === T_CLASS) {
    break;
    }

    if (strcasecmp($builtNamespace, $this->getNamespaceName()) === 0) {
    $matchedNamespace = true;
    }

    if ($matchedNamespace) {

    if ($token[0] === T_USE) {
    $record = 'class';
    }

    if ($token[0] === T_AS) {
    $record = 'as';
    }

    if ($record) {
    switch ($token[0]) {

    case T_STRING:
    case T_NS_SEPARATOR:

    if ($record) {
    $currentUse[$record] .= $token[1];
    }

    break;
    }
    }
    }

    if ($token[2] >= $this->getStartLine()) {
    break;
    }
    }


    // Make sure the as key has the name of the class even
    // if there is no alias in the use statement.
    foreach ($useStatements as &$useStatement) {

    if (empty($useStatement['as'])) {

    $useStatement['as'] = basename($useStatement['class']);
    }
    }

    return $useStatements;
    }


    /**
    * Return array of use statements from class.
    *
    * @return array
    */
    public function getUseStatements() {

    return $this->parseUseStatements();
    }


    /**
    * Check if class is using a class or an alias of a class.
    *
    * @param string $class
    * @return boolean
    */
    public function hasUseStatement($class) {

    $useStatements = $this->parseUseStatements();

    return
    array_search($class, array_column($useStatements, 'class')) ||
    array_search($class, array_column($useStatements, 'as'));
    }
    }
    64 changes: 64 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,64 @@
    # ExtendedReflectionClass

    This class was created from a need to get use statements and aliases from a class. The use statements are context sensitive. If there are multiple namespaces in the file, only the use statements from the namespace of the reflected class will be used.

    The class file is read only up to the point where the class is instantiated to save memory and speed up the parsing process on large class files.

    ## Usage

    I will eventually move this class to its own repository and add it to composer. Until then, here are some basic usage examples.

    ### MyCustomClass.php
    <?php

    namespace MyNamespace\Test;

    use FooNamespace\FooClass;
    use BarNamespace\BarClass as Bar;
    use BazNamespace\BazClass as BazSpecial;

    class MyCustomClass {

    protected $someDependencies = [];

    public function __construct(FooClass $foo, Bar $bar) {

    $someDependencies[] = $foo;
    $someDependencies[] = $bar;
    }
    }


    ### index.php
    <?php

    require 'ExtendedReflectionClass.php';
    require 'MyCustomClass.php';

    $class = new ExtendedReflectionClass('MyNamespace\Test\MyCustomClass');

    $class->getUseStatements();
    // [
    // [
    // 'class' => 'FooNamespace\FooClass',
    // 'as' => 'FooClass'
    // ],
    // [
    // 'class' => 'BarNamespace\BarClass',
    // 'as' => 'Bar'
    // ],
    // [
    // 'class' => 'BazNamespace\BazClass',
    // 'as' => 'BazSpecial'
    // ]
    // ]

    $class->hasUseStatement('FooClass'); // true
    $class->hasUseStatement('BarNamespace\BarClass'); // true
    $class->hasUseStatement('BazSpecial'); // true

    $class->hasUseStatement('SomeNamespace\SomeClass'); // false

    ## Disclaimer
    This was created as a proof of concept to answer my own [StackOverflow question](http://stackoverflow.com/questions/30308137/get-use-statement-from-class). As such, there are no tests or more comprehensive documentation. I will refine and release this class as a fully tested package soon. In the meantime, please have a look and tell me what you think.