PHP Autoloader - For classes, traits and interfaces











up vote
2
down vote

favorite












Please review my Autoloader, which is the first file included in index.php



Note that there is no resource with the same name for trait, interface and class. Each resource has it's own name. And even if some class is named "Ha" and some trait is named "Ha", one of them has specific namespace for this.



<?php
### Autoload class ###
class Autoload
{
# The path for classes, traits or interfaces #
private static $path = 'private/Model/';

# The resource files by default will be NULL #
private static $resource_files = null;

# Search for resource_files in recursive mode #
private static function recursive_glob($pattern)
{
$resource_files = glob($pattern);
foreach(glob(dirname($pattern).'/*', GLOB_ONLYDIR | GLOB_NOSORT) as $directory)
{
$resource_files = array_merge(
$resource_files,
self::recursive_glob($directory.'/'.basename($pattern))
);
}
return $resource_files;
}

# Order array to start with files that has the name like the $resource or closely... #
private static function order_resource_files($resource)
{
$resource_name = explode('\', $resource);
$resource_name = end($resource_name);

foreach(self::$resource_files as $file_key => $file)
{
if(stripos($file, $resource_name) !== false)
{
self::$resource_files[-1] = $file;
unset(self::$resource_files[$file_key]);

ksort(self::$resource_files);
self::$resource_files = array_values(self::$resource_files);
}
}
}

# Find resource #
public static function find($resource)
{
# Set $resource_files if is NULL #
if(!self::$resource_files)
{
self::$resource_files = self::recursive_glob(self::$path.'*.php');
}

# Order $resource_files by given resource #
self::order_resource_files($resource);

# Now that we have the $resource_files array, we can start searching #
foreach(self::$resource_files as $file_key => $file)
{
# First, remove the file from array #
unset(self::$resource_files[$file_key]);

# Include file #
require_once $file;

# If resource exists now, then we can stop and search for other resources later #
if(class_exists($resource) || trait_exists($resource) || interface_exists($resource))
{
break;
}
}
}
}

### Check PHP version and call Autoload::find ###
if(version_compare(PHP_VERSION, '5.1.2', '>='))
{
if(version_compare(PHP_VERSION, '5.3.0', '>='))
{
spl_autoload_register('Autoload::find', true, true);
}
else
{
spl_autoload_register('Autoload::find');
}
}
else
{
function __autoload($resource)
{
Autoload::find($resource);
}
}









share|improve this question
















bumped to the homepage by Community 27 mins ago


This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.



















    up vote
    2
    down vote

    favorite












    Please review my Autoloader, which is the first file included in index.php



    Note that there is no resource with the same name for trait, interface and class. Each resource has it's own name. And even if some class is named "Ha" and some trait is named "Ha", one of them has specific namespace for this.



    <?php
    ### Autoload class ###
    class Autoload
    {
    # The path for classes, traits or interfaces #
    private static $path = 'private/Model/';

    # The resource files by default will be NULL #
    private static $resource_files = null;

    # Search for resource_files in recursive mode #
    private static function recursive_glob($pattern)
    {
    $resource_files = glob($pattern);
    foreach(glob(dirname($pattern).'/*', GLOB_ONLYDIR | GLOB_NOSORT) as $directory)
    {
    $resource_files = array_merge(
    $resource_files,
    self::recursive_glob($directory.'/'.basename($pattern))
    );
    }
    return $resource_files;
    }

    # Order array to start with files that has the name like the $resource or closely... #
    private static function order_resource_files($resource)
    {
    $resource_name = explode('\', $resource);
    $resource_name = end($resource_name);

    foreach(self::$resource_files as $file_key => $file)
    {
    if(stripos($file, $resource_name) !== false)
    {
    self::$resource_files[-1] = $file;
    unset(self::$resource_files[$file_key]);

    ksort(self::$resource_files);
    self::$resource_files = array_values(self::$resource_files);
    }
    }
    }

    # Find resource #
    public static function find($resource)
    {
    # Set $resource_files if is NULL #
    if(!self::$resource_files)
    {
    self::$resource_files = self::recursive_glob(self::$path.'*.php');
    }

    # Order $resource_files by given resource #
    self::order_resource_files($resource);

    # Now that we have the $resource_files array, we can start searching #
    foreach(self::$resource_files as $file_key => $file)
    {
    # First, remove the file from array #
    unset(self::$resource_files[$file_key]);

    # Include file #
    require_once $file;

    # If resource exists now, then we can stop and search for other resources later #
    if(class_exists($resource) || trait_exists($resource) || interface_exists($resource))
    {
    break;
    }
    }
    }
    }

    ### Check PHP version and call Autoload::find ###
    if(version_compare(PHP_VERSION, '5.1.2', '>='))
    {
    if(version_compare(PHP_VERSION, '5.3.0', '>='))
    {
    spl_autoload_register('Autoload::find', true, true);
    }
    else
    {
    spl_autoload_register('Autoload::find');
    }
    }
    else
    {
    function __autoload($resource)
    {
    Autoload::find($resource);
    }
    }









    share|improve this question
















    bumped to the homepage by Community 27 mins ago


    This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.

















      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      Please review my Autoloader, which is the first file included in index.php



      Note that there is no resource with the same name for trait, interface and class. Each resource has it's own name. And even if some class is named "Ha" and some trait is named "Ha", one of them has specific namespace for this.



      <?php
      ### Autoload class ###
      class Autoload
      {
      # The path for classes, traits or interfaces #
      private static $path = 'private/Model/';

      # The resource files by default will be NULL #
      private static $resource_files = null;

      # Search for resource_files in recursive mode #
      private static function recursive_glob($pattern)
      {
      $resource_files = glob($pattern);
      foreach(glob(dirname($pattern).'/*', GLOB_ONLYDIR | GLOB_NOSORT) as $directory)
      {
      $resource_files = array_merge(
      $resource_files,
      self::recursive_glob($directory.'/'.basename($pattern))
      );
      }
      return $resource_files;
      }

      # Order array to start with files that has the name like the $resource or closely... #
      private static function order_resource_files($resource)
      {
      $resource_name = explode('\', $resource);
      $resource_name = end($resource_name);

      foreach(self::$resource_files as $file_key => $file)
      {
      if(stripos($file, $resource_name) !== false)
      {
      self::$resource_files[-1] = $file;
      unset(self::$resource_files[$file_key]);

      ksort(self::$resource_files);
      self::$resource_files = array_values(self::$resource_files);
      }
      }
      }

      # Find resource #
      public static function find($resource)
      {
      # Set $resource_files if is NULL #
      if(!self::$resource_files)
      {
      self::$resource_files = self::recursive_glob(self::$path.'*.php');
      }

      # Order $resource_files by given resource #
      self::order_resource_files($resource);

      # Now that we have the $resource_files array, we can start searching #
      foreach(self::$resource_files as $file_key => $file)
      {
      # First, remove the file from array #
      unset(self::$resource_files[$file_key]);

      # Include file #
      require_once $file;

      # If resource exists now, then we can stop and search for other resources later #
      if(class_exists($resource) || trait_exists($resource) || interface_exists($resource))
      {
      break;
      }
      }
      }
      }

      ### Check PHP version and call Autoload::find ###
      if(version_compare(PHP_VERSION, '5.1.2', '>='))
      {
      if(version_compare(PHP_VERSION, '5.3.0', '>='))
      {
      spl_autoload_register('Autoload::find', true, true);
      }
      else
      {
      spl_autoload_register('Autoload::find');
      }
      }
      else
      {
      function __autoload($resource)
      {
      Autoload::find($resource);
      }
      }









      share|improve this question















      Please review my Autoloader, which is the first file included in index.php



      Note that there is no resource with the same name for trait, interface and class. Each resource has it's own name. And even if some class is named "Ha" and some trait is named "Ha", one of them has specific namespace for this.



      <?php
      ### Autoload class ###
      class Autoload
      {
      # The path for classes, traits or interfaces #
      private static $path = 'private/Model/';

      # The resource files by default will be NULL #
      private static $resource_files = null;

      # Search for resource_files in recursive mode #
      private static function recursive_glob($pattern)
      {
      $resource_files = glob($pattern);
      foreach(glob(dirname($pattern).'/*', GLOB_ONLYDIR | GLOB_NOSORT) as $directory)
      {
      $resource_files = array_merge(
      $resource_files,
      self::recursive_glob($directory.'/'.basename($pattern))
      );
      }
      return $resource_files;
      }

      # Order array to start with files that has the name like the $resource or closely... #
      private static function order_resource_files($resource)
      {
      $resource_name = explode('\', $resource);
      $resource_name = end($resource_name);

      foreach(self::$resource_files as $file_key => $file)
      {
      if(stripos($file, $resource_name) !== false)
      {
      self::$resource_files[-1] = $file;
      unset(self::$resource_files[$file_key]);

      ksort(self::$resource_files);
      self::$resource_files = array_values(self::$resource_files);
      }
      }
      }

      # Find resource #
      public static function find($resource)
      {
      # Set $resource_files if is NULL #
      if(!self::$resource_files)
      {
      self::$resource_files = self::recursive_glob(self::$path.'*.php');
      }

      # Order $resource_files by given resource #
      self::order_resource_files($resource);

      # Now that we have the $resource_files array, we can start searching #
      foreach(self::$resource_files as $file_key => $file)
      {
      # First, remove the file from array #
      unset(self::$resource_files[$file_key]);

      # Include file #
      require_once $file;

      # If resource exists now, then we can stop and search for other resources later #
      if(class_exists($resource) || trait_exists($resource) || interface_exists($resource))
      {
      break;
      }
      }
      }
      }

      ### Check PHP version and call Autoload::find ###
      if(version_compare(PHP_VERSION, '5.1.2', '>='))
      {
      if(version_compare(PHP_VERSION, '5.3.0', '>='))
      {
      spl_autoload_register('Autoload::find', true, true);
      }
      else
      {
      spl_autoload_register('Autoload::find');
      }
      }
      else
      {
      function __autoload($resource)
      {
      Autoload::find($resource);
      }
      }






      php object-oriented library dynamic-loading






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited May 19 at 21:18









      200_success

      127k15148412




      127k15148412










      asked Feb 17 at 19:05









      Andrei

      111




      111





      bumped to the homepage by Community 27 mins ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.







      bumped to the homepage by Community 27 mins ago


      This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
























          2 Answers
          2






          active

          oldest

          votes

















          up vote
          0
          down vote













          First of all you should use static methods and properties only
          when there is good reason to do so. Generally you should default to non-static.





          1. $path property can be const because private static doesn't say whether it is immutable or not.

          2. I think you shouldn't order resource files at all. You already have resource name. All you should do is match something like $resource.'.' and include file if such exists. Also if you did require_once i don't see the need to check for class_exists() etc.


          3. I have never written autoloader but my instinct tells me that if you failed to find resource file then you should throw exception.


          4. Altering array inside foreach is murky and its good to avoid such practices.



          PS: Personally I haven't seen any php project/library utilizing hashtag comments. It might be my OCD but #...# draws all my focus so my suggestion is to use either: // for line comments and /*...*/ for block comments.



          Update:
          What I had in mind when writing point 2 is something like this:



              foreach(self::$resource_files as $file_key => $file)
          {
          // Check if resource matches file name
          if (strpos($file, $resource.'.') !== false ) {
          unset(self::$resource_files[$file_key]);

          require_once $file;
          }
          }





          share|improve this answer























          • 1. Yes. It can be const and I would do that ! 2. If you test the Autoloader you will see that there is a reason why I use class_exists etc. If I don't do that, the foreach will include all classes without any sense. This is also the reason why I reorder the array. 3. Yes, you are right ! 4. Yes, I know that altering array inside foreach sounds bad, but in my case it has a good point. If I don't delete array elements, then I will end including all files over and over. Thank you very much for your answer!
            – Andrei
            Feb 18 at 18:21


















          up vote
          0
          down vote













          First, I disagree with the comment of xReprisal about static. A Static method is a useful tool and spoiling it is a waste. However, you are also using a static field and it is not recommended (because it's not safe, at least on Java). I avoid (my example, see below) to use static by creating a new instance once.



          For this task, I create a project (free, MIT license) that it does the auto mapper



          https://github.com/EFTEC/AutoLoadOne



          It generates an automap from all the classes, interfaces and traits and it produces an autoload.php. It does the autoload the most efficiently possible (I hope). So it's a two stage program.



          About your code:



          a) PHP 5.6 will be close to being obsolete. So, I don't think it's worth to support an old version of PHP.



          b) You are scanning an entire folder (and their subfolders) each time you call a new class/interface/trait ($resource_files = glob($pattern); instead of self::resource_files i.e the recommendation of xReprisal). Even if you are doing the scan of the entire folder once, you are doing it once per customer per call. So it impacts the performance. If you can, you could cache the $self:: resource data on APCU, REDIS or even in a text field). What I did to solve it? pre-scan the folder once and for all by generating the class:



          The class has two arrays, one if for map classes that are specials such as classes in different folders or classes in the same .php file.
          And the second array has a map of namespaces and folders.



          It is how a generated autoload.php looks:



          <?php
          /**
          * This class is used for autocomplete.
          * Class _AutoLoad
          * @noautoload it avoids to index this class
          * @generated by AutoLoadOne 1.3 generated 2018/07/06 05:39:35
          * @copyright Copyright Jorge Castro C - MIT License. https://github.com/EFTEC/AutoLoadOne
          */
          class _AutoLoad
          {
          var $debug=false;
          private $_arrautoloadCustom = array(
          'MyProjectConnection' => '/../test/folder/multiplenamespace.php',
          'AnotherProjectConnection' => '/../test/folder/multiplenamespace.php',
          'MyProjectConnection2' => '/../test/folder/multiplenamespace2.php',
          'AnotherProjectConnection2' => '/../test/folder/multiplenamespace2.php',
          'ClassWithoutNameSpace' => '/../test/folder/subfolderalt/ClassWithoutNameSpace.php',
          'foldersubfolderCustomClass' => '/../test/folder/subfolderalt/CustomClass.php'
          );
          private $_arrautoload = array(
          'folder' => '/../test/folder',
          'foldersubfolder' => '/../test/folder/subfolder',
          'subsubsub' => '/../test/folder/subfolder/subsubfolder'
          );
          /**
          * _AutoLoad constructor.
          * @param bool $debug
          */
          public function __construct($debug=false)
          {
          $this->debug = $debug;
          }
          /**
          * @param $class_name
          * @throws Exception
          */
          public function auto($class_name) {
          // its called only if the class is not loaded.
          $ns = dirname($class_name); // without trailing
          $ns=($ns==".")?"":$ns;
          $cls = basename($class_name);
          // special cases
          if (isset($this->_arrautoloadCustom[$class_name])) {
          $this->loadIfExists($this->_arrautoloadCustom[$class_name] );
          return;
          }
          // normal (folder) cases
          if (isset($this->_arrautoload[$ns])) {
          $this->loadIfExists($this->_arrautoload[$ns] . "/" . $cls . ".php");
          return;
          }
          }

          /**
          * @param $filename
          * @throws Exception
          */
          public function loadIfExists($filename)
          {
          if((@include __DIR__."/".$filename) === false) {
          if ($this->debug) {
          throw new Exception("AutoLoadOne Error: Loading file [".__DIR__."/".$filename."] for class [".basename($filename)."]");
          } else {
          throw new Exception("AutoLoadOne Error: No file found.");
          }
          }
          }
          } // end of the class _AutoLoad
          if (defined('_AUTOLOADONEDEBUG')) {
          $_autoLoad=new _AutoLoad(_AUTOLOADONEDEBUG);
          } else {
          $_autoLoad=new _AutoLoad(false);
          }
          spl_autoload_register(function ($class_name)
          {
          global $_autoLoad;
          $_autoLoad->auto($class_name);
          });





          share|improve this answer























            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "196"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f187764%2fphp-autoloader-for-classes-traits-and-interfaces%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            0
            down vote













            First of all you should use static methods and properties only
            when there is good reason to do so. Generally you should default to non-static.





            1. $path property can be const because private static doesn't say whether it is immutable or not.

            2. I think you shouldn't order resource files at all. You already have resource name. All you should do is match something like $resource.'.' and include file if such exists. Also if you did require_once i don't see the need to check for class_exists() etc.


            3. I have never written autoloader but my instinct tells me that if you failed to find resource file then you should throw exception.


            4. Altering array inside foreach is murky and its good to avoid such practices.



            PS: Personally I haven't seen any php project/library utilizing hashtag comments. It might be my OCD but #...# draws all my focus so my suggestion is to use either: // for line comments and /*...*/ for block comments.



            Update:
            What I had in mind when writing point 2 is something like this:



                foreach(self::$resource_files as $file_key => $file)
            {
            // Check if resource matches file name
            if (strpos($file, $resource.'.') !== false ) {
            unset(self::$resource_files[$file_key]);

            require_once $file;
            }
            }





            share|improve this answer























            • 1. Yes. It can be const and I would do that ! 2. If you test the Autoloader you will see that there is a reason why I use class_exists etc. If I don't do that, the foreach will include all classes without any sense. This is also the reason why I reorder the array. 3. Yes, you are right ! 4. Yes, I know that altering array inside foreach sounds bad, but in my case it has a good point. If I don't delete array elements, then I will end including all files over and over. Thank you very much for your answer!
              – Andrei
              Feb 18 at 18:21















            up vote
            0
            down vote













            First of all you should use static methods and properties only
            when there is good reason to do so. Generally you should default to non-static.





            1. $path property can be const because private static doesn't say whether it is immutable or not.

            2. I think you shouldn't order resource files at all. You already have resource name. All you should do is match something like $resource.'.' and include file if such exists. Also if you did require_once i don't see the need to check for class_exists() etc.


            3. I have never written autoloader but my instinct tells me that if you failed to find resource file then you should throw exception.


            4. Altering array inside foreach is murky and its good to avoid such practices.



            PS: Personally I haven't seen any php project/library utilizing hashtag comments. It might be my OCD but #...# draws all my focus so my suggestion is to use either: // for line comments and /*...*/ for block comments.



            Update:
            What I had in mind when writing point 2 is something like this:



                foreach(self::$resource_files as $file_key => $file)
            {
            // Check if resource matches file name
            if (strpos($file, $resource.'.') !== false ) {
            unset(self::$resource_files[$file_key]);

            require_once $file;
            }
            }





            share|improve this answer























            • 1. Yes. It can be const and I would do that ! 2. If you test the Autoloader you will see that there is a reason why I use class_exists etc. If I don't do that, the foreach will include all classes without any sense. This is also the reason why I reorder the array. 3. Yes, you are right ! 4. Yes, I know that altering array inside foreach sounds bad, but in my case it has a good point. If I don't delete array elements, then I will end including all files over and over. Thank you very much for your answer!
              – Andrei
              Feb 18 at 18:21













            up vote
            0
            down vote










            up vote
            0
            down vote









            First of all you should use static methods and properties only
            when there is good reason to do so. Generally you should default to non-static.





            1. $path property can be const because private static doesn't say whether it is immutable or not.

            2. I think you shouldn't order resource files at all. You already have resource name. All you should do is match something like $resource.'.' and include file if such exists. Also if you did require_once i don't see the need to check for class_exists() etc.


            3. I have never written autoloader but my instinct tells me that if you failed to find resource file then you should throw exception.


            4. Altering array inside foreach is murky and its good to avoid such practices.



            PS: Personally I haven't seen any php project/library utilizing hashtag comments. It might be my OCD but #...# draws all my focus so my suggestion is to use either: // for line comments and /*...*/ for block comments.



            Update:
            What I had in mind when writing point 2 is something like this:



                foreach(self::$resource_files as $file_key => $file)
            {
            // Check if resource matches file name
            if (strpos($file, $resource.'.') !== false ) {
            unset(self::$resource_files[$file_key]);

            require_once $file;
            }
            }





            share|improve this answer














            First of all you should use static methods and properties only
            when there is good reason to do so. Generally you should default to non-static.





            1. $path property can be const because private static doesn't say whether it is immutable or not.

            2. I think you shouldn't order resource files at all. You already have resource name. All you should do is match something like $resource.'.' and include file if such exists. Also if you did require_once i don't see the need to check for class_exists() etc.


            3. I have never written autoloader but my instinct tells me that if you failed to find resource file then you should throw exception.


            4. Altering array inside foreach is murky and its good to avoid such practices.



            PS: Personally I haven't seen any php project/library utilizing hashtag comments. It might be my OCD but #...# draws all my focus so my suggestion is to use either: // for line comments and /*...*/ for block comments.



            Update:
            What I had in mind when writing point 2 is something like this:



                foreach(self::$resource_files as $file_key => $file)
            {
            // Check if resource matches file name
            if (strpos($file, $resource.'.') !== false ) {
            unset(self::$resource_files[$file_key]);

            require_once $file;
            }
            }






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Feb 18 at 19:57

























            answered Feb 18 at 15:23









            xReprisal

            29114




            29114












            • 1. Yes. It can be const and I would do that ! 2. If you test the Autoloader you will see that there is a reason why I use class_exists etc. If I don't do that, the foreach will include all classes without any sense. This is also the reason why I reorder the array. 3. Yes, you are right ! 4. Yes, I know that altering array inside foreach sounds bad, but in my case it has a good point. If I don't delete array elements, then I will end including all files over and over. Thank you very much for your answer!
              – Andrei
              Feb 18 at 18:21


















            • 1. Yes. It can be const and I would do that ! 2. If you test the Autoloader you will see that there is a reason why I use class_exists etc. If I don't do that, the foreach will include all classes without any sense. This is also the reason why I reorder the array. 3. Yes, you are right ! 4. Yes, I know that altering array inside foreach sounds bad, but in my case it has a good point. If I don't delete array elements, then I will end including all files over and over. Thank you very much for your answer!
              – Andrei
              Feb 18 at 18:21
















            1. Yes. It can be const and I would do that ! 2. If you test the Autoloader you will see that there is a reason why I use class_exists etc. If I don't do that, the foreach will include all classes without any sense. This is also the reason why I reorder the array. 3. Yes, you are right ! 4. Yes, I know that altering array inside foreach sounds bad, but in my case it has a good point. If I don't delete array elements, then I will end including all files over and over. Thank you very much for your answer!
            – Andrei
            Feb 18 at 18:21




            1. Yes. It can be const and I would do that ! 2. If you test the Autoloader you will see that there is a reason why I use class_exists etc. If I don't do that, the foreach will include all classes without any sense. This is also the reason why I reorder the array. 3. Yes, you are right ! 4. Yes, I know that altering array inside foreach sounds bad, but in my case it has a good point. If I don't delete array elements, then I will end including all files over and over. Thank you very much for your answer!
            – Andrei
            Feb 18 at 18:21












            up vote
            0
            down vote













            First, I disagree with the comment of xReprisal about static. A Static method is a useful tool and spoiling it is a waste. However, you are also using a static field and it is not recommended (because it's not safe, at least on Java). I avoid (my example, see below) to use static by creating a new instance once.



            For this task, I create a project (free, MIT license) that it does the auto mapper



            https://github.com/EFTEC/AutoLoadOne



            It generates an automap from all the classes, interfaces and traits and it produces an autoload.php. It does the autoload the most efficiently possible (I hope). So it's a two stage program.



            About your code:



            a) PHP 5.6 will be close to being obsolete. So, I don't think it's worth to support an old version of PHP.



            b) You are scanning an entire folder (and their subfolders) each time you call a new class/interface/trait ($resource_files = glob($pattern); instead of self::resource_files i.e the recommendation of xReprisal). Even if you are doing the scan of the entire folder once, you are doing it once per customer per call. So it impacts the performance. If you can, you could cache the $self:: resource data on APCU, REDIS or even in a text field). What I did to solve it? pre-scan the folder once and for all by generating the class:



            The class has two arrays, one if for map classes that are specials such as classes in different folders or classes in the same .php file.
            And the second array has a map of namespaces and folders.



            It is how a generated autoload.php looks:



            <?php
            /**
            * This class is used for autocomplete.
            * Class _AutoLoad
            * @noautoload it avoids to index this class
            * @generated by AutoLoadOne 1.3 generated 2018/07/06 05:39:35
            * @copyright Copyright Jorge Castro C - MIT License. https://github.com/EFTEC/AutoLoadOne
            */
            class _AutoLoad
            {
            var $debug=false;
            private $_arrautoloadCustom = array(
            'MyProjectConnection' => '/../test/folder/multiplenamespace.php',
            'AnotherProjectConnection' => '/../test/folder/multiplenamespace.php',
            'MyProjectConnection2' => '/../test/folder/multiplenamespace2.php',
            'AnotherProjectConnection2' => '/../test/folder/multiplenamespace2.php',
            'ClassWithoutNameSpace' => '/../test/folder/subfolderalt/ClassWithoutNameSpace.php',
            'foldersubfolderCustomClass' => '/../test/folder/subfolderalt/CustomClass.php'
            );
            private $_arrautoload = array(
            'folder' => '/../test/folder',
            'foldersubfolder' => '/../test/folder/subfolder',
            'subsubsub' => '/../test/folder/subfolder/subsubfolder'
            );
            /**
            * _AutoLoad constructor.
            * @param bool $debug
            */
            public function __construct($debug=false)
            {
            $this->debug = $debug;
            }
            /**
            * @param $class_name
            * @throws Exception
            */
            public function auto($class_name) {
            // its called only if the class is not loaded.
            $ns = dirname($class_name); // without trailing
            $ns=($ns==".")?"":$ns;
            $cls = basename($class_name);
            // special cases
            if (isset($this->_arrautoloadCustom[$class_name])) {
            $this->loadIfExists($this->_arrautoloadCustom[$class_name] );
            return;
            }
            // normal (folder) cases
            if (isset($this->_arrautoload[$ns])) {
            $this->loadIfExists($this->_arrautoload[$ns] . "/" . $cls . ".php");
            return;
            }
            }

            /**
            * @param $filename
            * @throws Exception
            */
            public function loadIfExists($filename)
            {
            if((@include __DIR__."/".$filename) === false) {
            if ($this->debug) {
            throw new Exception("AutoLoadOne Error: Loading file [".__DIR__."/".$filename."] for class [".basename($filename)."]");
            } else {
            throw new Exception("AutoLoadOne Error: No file found.");
            }
            }
            }
            } // end of the class _AutoLoad
            if (defined('_AUTOLOADONEDEBUG')) {
            $_autoLoad=new _AutoLoad(_AUTOLOADONEDEBUG);
            } else {
            $_autoLoad=new _AutoLoad(false);
            }
            spl_autoload_register(function ($class_name)
            {
            global $_autoLoad;
            $_autoLoad->auto($class_name);
            });





            share|improve this answer



























              up vote
              0
              down vote













              First, I disagree with the comment of xReprisal about static. A Static method is a useful tool and spoiling it is a waste. However, you are also using a static field and it is not recommended (because it's not safe, at least on Java). I avoid (my example, see below) to use static by creating a new instance once.



              For this task, I create a project (free, MIT license) that it does the auto mapper



              https://github.com/EFTEC/AutoLoadOne



              It generates an automap from all the classes, interfaces and traits and it produces an autoload.php. It does the autoload the most efficiently possible (I hope). So it's a two stage program.



              About your code:



              a) PHP 5.6 will be close to being obsolete. So, I don't think it's worth to support an old version of PHP.



              b) You are scanning an entire folder (and their subfolders) each time you call a new class/interface/trait ($resource_files = glob($pattern); instead of self::resource_files i.e the recommendation of xReprisal). Even if you are doing the scan of the entire folder once, you are doing it once per customer per call. So it impacts the performance. If you can, you could cache the $self:: resource data on APCU, REDIS or even in a text field). What I did to solve it? pre-scan the folder once and for all by generating the class:



              The class has two arrays, one if for map classes that are specials such as classes in different folders or classes in the same .php file.
              And the second array has a map of namespaces and folders.



              It is how a generated autoload.php looks:



              <?php
              /**
              * This class is used for autocomplete.
              * Class _AutoLoad
              * @noautoload it avoids to index this class
              * @generated by AutoLoadOne 1.3 generated 2018/07/06 05:39:35
              * @copyright Copyright Jorge Castro C - MIT License. https://github.com/EFTEC/AutoLoadOne
              */
              class _AutoLoad
              {
              var $debug=false;
              private $_arrautoloadCustom = array(
              'MyProjectConnection' => '/../test/folder/multiplenamespace.php',
              'AnotherProjectConnection' => '/../test/folder/multiplenamespace.php',
              'MyProjectConnection2' => '/../test/folder/multiplenamespace2.php',
              'AnotherProjectConnection2' => '/../test/folder/multiplenamespace2.php',
              'ClassWithoutNameSpace' => '/../test/folder/subfolderalt/ClassWithoutNameSpace.php',
              'foldersubfolderCustomClass' => '/../test/folder/subfolderalt/CustomClass.php'
              );
              private $_arrautoload = array(
              'folder' => '/../test/folder',
              'foldersubfolder' => '/../test/folder/subfolder',
              'subsubsub' => '/../test/folder/subfolder/subsubfolder'
              );
              /**
              * _AutoLoad constructor.
              * @param bool $debug
              */
              public function __construct($debug=false)
              {
              $this->debug = $debug;
              }
              /**
              * @param $class_name
              * @throws Exception
              */
              public function auto($class_name) {
              // its called only if the class is not loaded.
              $ns = dirname($class_name); // without trailing
              $ns=($ns==".")?"":$ns;
              $cls = basename($class_name);
              // special cases
              if (isset($this->_arrautoloadCustom[$class_name])) {
              $this->loadIfExists($this->_arrautoloadCustom[$class_name] );
              return;
              }
              // normal (folder) cases
              if (isset($this->_arrautoload[$ns])) {
              $this->loadIfExists($this->_arrautoload[$ns] . "/" . $cls . ".php");
              return;
              }
              }

              /**
              * @param $filename
              * @throws Exception
              */
              public function loadIfExists($filename)
              {
              if((@include __DIR__."/".$filename) === false) {
              if ($this->debug) {
              throw new Exception("AutoLoadOne Error: Loading file [".__DIR__."/".$filename."] for class [".basename($filename)."]");
              } else {
              throw new Exception("AutoLoadOne Error: No file found.");
              }
              }
              }
              } // end of the class _AutoLoad
              if (defined('_AUTOLOADONEDEBUG')) {
              $_autoLoad=new _AutoLoad(_AUTOLOADONEDEBUG);
              } else {
              $_autoLoad=new _AutoLoad(false);
              }
              spl_autoload_register(function ($class_name)
              {
              global $_autoLoad;
              $_autoLoad->auto($class_name);
              });





              share|improve this answer

























                up vote
                0
                down vote










                up vote
                0
                down vote









                First, I disagree with the comment of xReprisal about static. A Static method is a useful tool and spoiling it is a waste. However, you are also using a static field and it is not recommended (because it's not safe, at least on Java). I avoid (my example, see below) to use static by creating a new instance once.



                For this task, I create a project (free, MIT license) that it does the auto mapper



                https://github.com/EFTEC/AutoLoadOne



                It generates an automap from all the classes, interfaces and traits and it produces an autoload.php. It does the autoload the most efficiently possible (I hope). So it's a two stage program.



                About your code:



                a) PHP 5.6 will be close to being obsolete. So, I don't think it's worth to support an old version of PHP.



                b) You are scanning an entire folder (and their subfolders) each time you call a new class/interface/trait ($resource_files = glob($pattern); instead of self::resource_files i.e the recommendation of xReprisal). Even if you are doing the scan of the entire folder once, you are doing it once per customer per call. So it impacts the performance. If you can, you could cache the $self:: resource data on APCU, REDIS or even in a text field). What I did to solve it? pre-scan the folder once and for all by generating the class:



                The class has two arrays, one if for map classes that are specials such as classes in different folders or classes in the same .php file.
                And the second array has a map of namespaces and folders.



                It is how a generated autoload.php looks:



                <?php
                /**
                * This class is used for autocomplete.
                * Class _AutoLoad
                * @noautoload it avoids to index this class
                * @generated by AutoLoadOne 1.3 generated 2018/07/06 05:39:35
                * @copyright Copyright Jorge Castro C - MIT License. https://github.com/EFTEC/AutoLoadOne
                */
                class _AutoLoad
                {
                var $debug=false;
                private $_arrautoloadCustom = array(
                'MyProjectConnection' => '/../test/folder/multiplenamespace.php',
                'AnotherProjectConnection' => '/../test/folder/multiplenamespace.php',
                'MyProjectConnection2' => '/../test/folder/multiplenamespace2.php',
                'AnotherProjectConnection2' => '/../test/folder/multiplenamespace2.php',
                'ClassWithoutNameSpace' => '/../test/folder/subfolderalt/ClassWithoutNameSpace.php',
                'foldersubfolderCustomClass' => '/../test/folder/subfolderalt/CustomClass.php'
                );
                private $_arrautoload = array(
                'folder' => '/../test/folder',
                'foldersubfolder' => '/../test/folder/subfolder',
                'subsubsub' => '/../test/folder/subfolder/subsubfolder'
                );
                /**
                * _AutoLoad constructor.
                * @param bool $debug
                */
                public function __construct($debug=false)
                {
                $this->debug = $debug;
                }
                /**
                * @param $class_name
                * @throws Exception
                */
                public function auto($class_name) {
                // its called only if the class is not loaded.
                $ns = dirname($class_name); // without trailing
                $ns=($ns==".")?"":$ns;
                $cls = basename($class_name);
                // special cases
                if (isset($this->_arrautoloadCustom[$class_name])) {
                $this->loadIfExists($this->_arrautoloadCustom[$class_name] );
                return;
                }
                // normal (folder) cases
                if (isset($this->_arrautoload[$ns])) {
                $this->loadIfExists($this->_arrautoload[$ns] . "/" . $cls . ".php");
                return;
                }
                }

                /**
                * @param $filename
                * @throws Exception
                */
                public function loadIfExists($filename)
                {
                if((@include __DIR__."/".$filename) === false) {
                if ($this->debug) {
                throw new Exception("AutoLoadOne Error: Loading file [".__DIR__."/".$filename."] for class [".basename($filename)."]");
                } else {
                throw new Exception("AutoLoadOne Error: No file found.");
                }
                }
                }
                } // end of the class _AutoLoad
                if (defined('_AUTOLOADONEDEBUG')) {
                $_autoLoad=new _AutoLoad(_AUTOLOADONEDEBUG);
                } else {
                $_autoLoad=new _AutoLoad(false);
                }
                spl_autoload_register(function ($class_name)
                {
                global $_autoLoad;
                $_autoLoad->auto($class_name);
                });





                share|improve this answer














                First, I disagree with the comment of xReprisal about static. A Static method is a useful tool and spoiling it is a waste. However, you are also using a static field and it is not recommended (because it's not safe, at least on Java). I avoid (my example, see below) to use static by creating a new instance once.



                For this task, I create a project (free, MIT license) that it does the auto mapper



                https://github.com/EFTEC/AutoLoadOne



                It generates an automap from all the classes, interfaces and traits and it produces an autoload.php. It does the autoload the most efficiently possible (I hope). So it's a two stage program.



                About your code:



                a) PHP 5.6 will be close to being obsolete. So, I don't think it's worth to support an old version of PHP.



                b) You are scanning an entire folder (and their subfolders) each time you call a new class/interface/trait ($resource_files = glob($pattern); instead of self::resource_files i.e the recommendation of xReprisal). Even if you are doing the scan of the entire folder once, you are doing it once per customer per call. So it impacts the performance. If you can, you could cache the $self:: resource data on APCU, REDIS or even in a text field). What I did to solve it? pre-scan the folder once and for all by generating the class:



                The class has two arrays, one if for map classes that are specials such as classes in different folders or classes in the same .php file.
                And the second array has a map of namespaces and folders.



                It is how a generated autoload.php looks:



                <?php
                /**
                * This class is used for autocomplete.
                * Class _AutoLoad
                * @noautoload it avoids to index this class
                * @generated by AutoLoadOne 1.3 generated 2018/07/06 05:39:35
                * @copyright Copyright Jorge Castro C - MIT License. https://github.com/EFTEC/AutoLoadOne
                */
                class _AutoLoad
                {
                var $debug=false;
                private $_arrautoloadCustom = array(
                'MyProjectConnection' => '/../test/folder/multiplenamespace.php',
                'AnotherProjectConnection' => '/../test/folder/multiplenamespace.php',
                'MyProjectConnection2' => '/../test/folder/multiplenamespace2.php',
                'AnotherProjectConnection2' => '/../test/folder/multiplenamespace2.php',
                'ClassWithoutNameSpace' => '/../test/folder/subfolderalt/ClassWithoutNameSpace.php',
                'foldersubfolderCustomClass' => '/../test/folder/subfolderalt/CustomClass.php'
                );
                private $_arrautoload = array(
                'folder' => '/../test/folder',
                'foldersubfolder' => '/../test/folder/subfolder',
                'subsubsub' => '/../test/folder/subfolder/subsubfolder'
                );
                /**
                * _AutoLoad constructor.
                * @param bool $debug
                */
                public function __construct($debug=false)
                {
                $this->debug = $debug;
                }
                /**
                * @param $class_name
                * @throws Exception
                */
                public function auto($class_name) {
                // its called only if the class is not loaded.
                $ns = dirname($class_name); // without trailing
                $ns=($ns==".")?"":$ns;
                $cls = basename($class_name);
                // special cases
                if (isset($this->_arrautoloadCustom[$class_name])) {
                $this->loadIfExists($this->_arrautoloadCustom[$class_name] );
                return;
                }
                // normal (folder) cases
                if (isset($this->_arrautoload[$ns])) {
                $this->loadIfExists($this->_arrautoload[$ns] . "/" . $cls . ".php");
                return;
                }
                }

                /**
                * @param $filename
                * @throws Exception
                */
                public function loadIfExists($filename)
                {
                if((@include __DIR__."/".$filename) === false) {
                if ($this->debug) {
                throw new Exception("AutoLoadOne Error: Loading file [".__DIR__."/".$filename."] for class [".basename($filename)."]");
                } else {
                throw new Exception("AutoLoadOne Error: No file found.");
                }
                }
                }
                } // end of the class _AutoLoad
                if (defined('_AUTOLOADONEDEBUG')) {
                $_autoLoad=new _AutoLoad(_AUTOLOADONEDEBUG);
                } else {
                $_autoLoad=new _AutoLoad(false);
                }
                spl_autoload_register(function ($class_name)
                {
                global $_autoLoad;
                $_autoLoad->auto($class_name);
                });






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jul 6 at 21:14

























                answered Jul 6 at 21:09









                magallanes

                1012




                1012






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    Use MathJax to format equations. MathJax reference.


                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f187764%2fphp-autoloader-for-classes-traits-and-interfaces%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Ottavio Pratesi

                    Tricia Helfer

                    15 giugno