Flexible __autoload scheme

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Berislav Lopac

    Flexible __autoload scheme

    With the advent of PHP5, with its OO support and the new __autoload
    function, I was thinking of implementing some king of scheme to organize
    classes in such a way that they can be easily found by the __autoload
    function, yet at the same time would have clear organization of classes.

    Currently (in PHP4) I'm using a Java-like scheme, borrowed from ActiveLink
    IORCA (www.active-link.com), which uses a special import() function and
    classes organized in files and directories. Each time I need a certain
    class, I must manually import the appropriate class or package. This works
    nicely, and intuitively especially for those with experience in Java, but as
    PHP5 offers us such a nice feature as the __autoload function, I would much
    prefer to take advantag of it.

    For those who don't know, __autoload is a magical function that is called
    each time a previously undefined class, with the called class name passed as
    the argument. Andi and Zeev in their upcoming book (see
    http://www.zend.com/php5/andi-book-excerpt.php) give the simplest example:

    function __autoload($cla ss_name) {
    include_once($c lass_name . "php");
    }

    However, this leads to a clutter of class files in a single directory, and
    the whole system calls for a little more organization. First of all, I would
    at least change the above code to:

    define('AUTOLOA D_CLASS_DIR', '/classes/');

    function __autoload($cla ss_name) {
    require_once(AU TOLOAD_CLASS_DI R . $class_name . ".class.php ");
    }

    This would give me a single central classes directory where all my classes
    are stored, as well as a distinct extension (class.php) for class files;
    also the class file is now required instead of included. However, it is
    still a bit spartan: what if I want to organize my classes by projects,
    package etc?

    I was thinking of a system where all the class.php files would be organized
    in directories, and the __autoload function would somehow be able to find
    the right one.

    Going through all the directories would potentionally be too slow,
    especially in a large classes hierarchy. One approach is that the __autoload
    includes a file defining an array which effectively mirrors the filesystem
    structure. This means that we need to edit the array each time we add (or
    move) a class, or perhaps implementing a mechanism that would, if a class
    isn't found, swoop through the directories and recreate the structure.
    Another downside would still remain, which is that each class would still
    have to have a different name to be recognized by the system.

    This seems like it might work (I still have to write it, though), but I am
    curious if anyone has some different and preferably better idea to implement
    this.

    Berislav

    --
    If the Internet is a Marx Brothers movie, and Web, e-mail, and IRC are
    Groucho, Chico, and Harpo, then Usenet is Zeppo.


  • Janwillem Borleffs

    #2
    Re: Flexible __autoload scheme

    Berislav Lopac wrote:[color=blue]
    > This would give me a single central classes directory where all my
    > classes are stored, as well as a distinct extension (class.php) for
    > class files; also the class file is now required instead of included.
    > However, it is still a bit spartan: what if I want to organize my
    > classes by projects, package etc?
    >[/color]

    You could use a naming convention for your classes like:

    Package_class.p hp

    and apply the __autoload method as follows:

    function __autoload($cla ss) {
    list($package, $name) = explode("_", $class, 2);
    include "{$package}/{$name}.php";
    }

    Now, if you want to include a class named Net_HTTP, it will include
    HTTP.php, which should reside in a dir called Net.

    Of course, the class defined in HTTP.php should also have the name Net_HTTP.

    Another possibility would be to adapt the way PEAR handles this...


    JW



    Comment

    • Berislav Lopac

      #3
      Re: Flexible __autoload scheme

      Janwillem Borleffs wrote:[color=blue]
      > Another possibility would be to adapt the way PEAR handles this...[/color]

      Which is?

      Berislav

      --
      If the Internet is a Marx Brothers movie, and Web, e-mail, and IRC are
      Groucho, Chico, and Harpo, then Usenet is Zeppo.


      Comment

      • Janwillem Borleffs

        #4
        Re: Flexible __autoload scheme

        Berislav Lopac wrote:[color=blue]
        > Janwillem Borleffs wrote:[color=green]
        >> Another possibility would be to adapt the way PEAR handles this...[/color]
        >
        > Which is?
        >[/color]

        Never looked at the PEAR library? In short it goes like this:

        * The include_path directive points to the PEAR installation dir (contains
        all classes)
        * Example structure:

        Net.php
        HTTP/
        HTTP/HTTP.php

        * Net.php is the parent class which contains all base methods
        * HTTP.php extends Net.php
        * The script that implements the Net::HTTP class includes "HTTP/HTTP.php"

        Quite basic, but it does enforce a clear structure for your classes.

        Until PHP supports namespaces like Java and Perl do, there aren't many
        options.


        JW



        Comment

        • Berislav Lopac

          #5
          Re: Flexible __autoload scheme

          Janwillem Borleffs wrote:[color=blue]
          >
          > Until PHP supports namespaces like Java and Perl do, there aren't many
          > options.[/color]

          I don't really see how would that help with the __autoload concept.

          Tangential to this, I'm not that big a fan of namespaces, as they promote
          some bad programming habits, while come handy not that often.

          Berislav

          --
          If the Internet is a Marx Brothers movie, and Web, e-mail, and IRC are
          Groucho, Chico, and Harpo, then Usenet is Zeppo.


          Comment

          • Qiang Xue

            #6
            Re: Flexible __autoload scheme


            "Berislav Lopac" <berislav.lopac @dimedia.hr> wrote in message news:chmqt6$n12 $1@ls219.htnet. hr...[color=blue]
            > With the advent of PHP5, with its OO support and the new __autoload
            > function, I was thinking of implementing some king of scheme to organize
            > classes in such a way that they can be easily found by the __autoload
            > function, yet at the same time would have clear organization of classes.
            >
            > Currently (in PHP4) I'm using a Java-like scheme, borrowed from ActiveLink
            > IORCA (www.active-link.com), which uses a special import() function and
            > classes organized in files and directories. Each time I need a certain
            > class, I must manually import the appropriate class or package. This works
            > nicely, and intuitively especially for those with experience in Java, but as
            > PHP5 offers us such a nice feature as the __autoload function, I would much
            > prefer to take advantag of it.
            >
            > For those who don't know, __autoload is a magical function that is called
            > each time a previously undefined class, with the called class name passed as
            > the argument. Andi and Zeev in their upcoming book (see
            > http://www.zend.com/php5/andi-book-excerpt.php) give the simplest example:
            >
            > function __autoload($cla ss_name) {
            > include_once($c lass_name . "php");
            > }
            >
            > However, this leads to a clutter of class files in a single directory, and
            > the whole system calls for a little more organization. First of all, I would
            > at least change the above code to:
            >
            > define('AUTOLOA D_CLASS_DIR', '/classes/');
            >
            > function __autoload($cla ss_name) {
            > require_once(AU TOLOAD_CLASS_DI R . $class_name . ".class.php ");
            > }
            >
            > This would give me a single central classes directory where all my classes
            > are stored, as well as a distinct extension (class.php) for class files;
            > also the class file is now required instead of included. However, it is
            > still a bit spartan: what if I want to organize my classes by projects,
            > package etc?
            >
            > I was thinking of a system where all the class.php files would be organized
            > in directories, and the __autoload function would somehow be able to find
            > the right one.
            >
            > Going through all the directories would potentionally be too slow,
            > especially in a large classes hierarchy. One approach is that the __autoload
            > includes a file defining an array which effectively mirrors the filesystem
            > structure. This means that we need to edit the array each time we add (or
            > move) a class, or perhaps implementing a mechanism that would, if a class
            > isn't found, swoop through the directories and recreate the structure.
            > Another downside would still remain, which is that each class would still
            > have to have a different name to be recognized by the system.
            >
            > This seems like it might work (I still have to write it, though), but I am
            > curious if anyone has some different and preferably better idea to implement
            > this.
            >
            > Berislav
            >
            > --
            > If the Internet is a Marx Brothers movie, and Web, e-mail, and IRC are
            > Groucho, Chico, and Harpo, then Usenet is Zeppo.
            >
            >[/color]

            I also want to know how to nicely deal with this problem.
            My current approach is a mixed one which is like Java searching for
            relevant class files according to classpath.
            The classpath is a sequence of search paths and files, where
            a search file is a mapping between class names and class file locations.
            Caching technique is used to save time for repetitive inclusion
            of the same classes.


            Comment

            • Tim Van Wassenhove

              #7
              Re: Flexible __autoload scheme

              In article <chmqt6$n12$1@l s219.htnet.hr>, Berislav Lopac wrote:[color=blue]
              > With the advent of PHP5, with its OO support and the new __autoload
              > function, I was thinking of implementing some king of scheme to organize
              > classes in such a way that they can be easily found by the __autoload
              > function, yet at the same time would have clear organization of classes.[/color]


              Don't know if the following would work in that case:
              $bigInt = new Math_BigInteger ();

              Would allow you to store BigInteger.clas s.php in a $include_path$/Math
              directory.

              function __autoload($cla ss)
              {
              return using($class);
              }

              function using($class)
              {

              $class = str_replace('_' , '/', $class);

              $include_path = ini_get('includ e_path');
              $paths = explode(':', $include_path);

              foreach($paths as $path)
              {
              if (file_exists($p ath . $class . '.class.php'))
              {
              require_once($p ath . $class . '.class.php');
              return true;
              }
              }
              trigger_error(" Class {$path}{$class} .class.php not found.", E_USER_ERROR);
              }

              --
              Tim Van Wassenhove <http://home.mysth.be/~timvw>

              Comment

              • R. Rajesh Jeba Anbiah

                #8
                Re: Flexible __autoload scheme

                Tim Van Wassenhove <euki@pi.be> wrote in message news:<2q9c88Ft6 be4U1@uni-berlin.de>...
                <snip>[color=blue]
                > function using($class)
                > {
                >
                > $class = str_replace('_' , '/', $class);
                >
                > $include_path = ini_get('includ e_path');
                > $paths = explode(':', $include_path);
                >
                > foreach($paths as $path)
                > {
                > if (file_exists($p ath . $class . '.class.php'))
                > {
                > require_once($p ath . $class . '.class.php');
                > return true;
                > }
                > }
                > trigger_error(" Class {$path}{$class} .class.php not found.", E_USER_ERROR);
                > }[/color]

                Hmm... I guess, you're duplicating the code. When you invoke,
                include or require, it will search the file in _all_
                "include_path"( s). Isn't it? Please correct me, if I'm wrong.

                --
                | Just another PHP saint |
                Email: rrjanbiah-at-Y!com

                Comment

                • Zurab Davitiani

                  #9
                  Re: Flexible __autoload scheme

                  Berislav Lopac wrote:
                  [color=blue]
                  > With the advent of PHP5, with its OO support and the new __autoload
                  > function, I was thinking of implementing some king of scheme to organize
                  > classes in such a way that they can be easily found by the __autoload
                  > function, yet at the same time would have clear organization of classes.
                  >
                  > Currently (in PHP4) I'm using a Java-like scheme, borrowed from ActiveLink
                  > IORCA (www.active-link.com), which uses a special import() function and
                  > classes organized in files and directories. Each time I need a certain
                  > class, I must manually import the appropriate class or package. This works
                  > nicely, and intuitively especially for those with experience in Java, but
                  > as PHP5 offers us such a nice feature as the __autoload function, I would
                  > much prefer to take advantag of it.[/color]

                  There are couple of options.

                  1. First of all, one option is like PEAR does it as others already pointed
                  out - i.e. replacing _ from a class name with / and loading a class from a
                  directory. So, if you have

                  $myHTTPClient = new net_http_HTTPCl ient;

                  then you would load

                  net/http/HTTPClient.php

                  However, I personally don't really prefer this model. I believe that it's
                  extremely important to explicitly state what the dependencies of a
                  particular class/script/etc. are. So, anything that discourages this
                  behavior I would try to avoid.

                  So, my other suggestion is:

                  2. Parse for * in import function of ActiveLink IORCA. If you find "*" then
                  add that directory to an array of dirs to autoload from. So, if you have:

                  import("org.act ive-link.xml.*);

                  then

                  $myXML = new XML();
                  $myXMLDoc = new XMLDoc();

                  should autoload from org/active-link/xml directory.

                  This way, you don't have to parse through all the directory tree for all
                  classes, and you don't have to import each class individually from one
                  package.

                  Hope this helps.

                  Disclaimer: I am the author of ActiveLink IORCA and ActiveLink PHP XML
                  Package ;)

                  Comment

                  • Tim Van Wassenhove

                    #10
                    Re: Flexible __autoload scheme

                    In article <abc4d8b8.04090 82048.2983e98f@ posting.google. com>, R. Rajesh Jeba Anbiah wrote:[color=blue]
                    > Tim Van Wassenhove <euki@pi.be> wrote in message news:<2q9c88Ft6 be4U1@uni-berlin.de>...
                    > <snip>[color=green]
                    >> function using($class)
                    >> {
                    >>
                    >> $class = '/' . str_replace('_' , '/', $class);
                    >>
                    >> $include_path = ini_get('includ e_path');
                    >> $paths = explode(':', $include_path);
                    >>
                    >> foreach($paths as $path)
                    >> {
                    >> if (file_exists($p ath . $class . '.class.php'))
                    >> {
                    >> require_once($p ath . $class . '.class.php');
                    >> return true;
                    >> }
                    >> }
                    >> trigger_error(" Class {$path}{$class} .class.php not found.", E_USER_ERROR);
                    >> }[/color]
                    >
                    > Hmm... I guess, you're duplicating the code. When you invoke,
                    > include or require, it will search the file in _all_
                    > "include_path"( s). Isn't it? Please correct me, if I'm wrong.[/color]

                    Good point there :)

                    I've been thinking about __autoload and untill now i don't see how this
                    function could be really usefull. (Only how it probably generates
                    overhead)

                    --
                    Tim Van Wassenhove <http://home.mysth.be/~timvw>

                    Comment

                    • Berislav Lopac

                      #11
                      Re: Flexible __autoload scheme

                      Zurab Davitiani wrote:[color=blue]
                      > So, my other suggestion is:
                      >
                      > 2. Parse for * in import function of ActiveLink IORCA. If you find
                      > "*" then add that directory to an array of dirs to autoload from. So,
                      > if you have:
                      >
                      > import("org.act ive-link.xml.*);
                      >
                      > then
                      >
                      > $myXML = new XML();
                      > $myXMLDoc = new XMLDoc();
                      >
                      > should autoload from org/active-link/xml directory.
                      >
                      > This way, you don't have to parse through all the directory tree for
                      > all classes, and you don't have to import each class individually
                      > from one package.
                      >
                      > Hope this helps.
                      >
                      > Disclaimer: I am the author of ActiveLink IORCA and ActiveLink PHP XML
                      > Package ;)[/color]

                      I already did as you suggest -- here's the complete code of my modification
                      at the end of this post (sorry I didn't properly mark what is the original
                      and what I added). You'll notice that I've added a nice red error message in
                      HTML when the class file wasn't found.

                      I am very grateful for your script, as it gave me a great boost when I
                      created my internal little framework. I'll keep using it even with PHP5, but
                      I'd still like to make use of __autoload somehow.

                      Berislav

                      PS. Here's the code:

                      <?php

                      /*
                      This file is part of ActiveLink IORCA (www.active-link.com).
                      Copyright (c) 2002-2003 by Zurab Davitiani

                      You can contact the author of this software via E-mail at
                      agt@mindless.co m

                      ActiveLink IORCA is free software; you can redistribute it and/or modify
                      it under the terms of the GNU General Public License as published by
                      the Free Software Foundation; either version 2 of the License, or
                      (at your option) any later version.

                      ActiveLink IORCA is distributed in the hope that it will be useful,
                      but WITHOUT ANY WARRANTY; without even the implied warranty of
                      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
                      GNU General Public License for more details.

                      You should have received a copy of the GNU General Public License
                      along with ActiveLink IORCA; if not, write to the Free Software
                      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
                      */

                      /**
                      * Include file for ActiveLink IORCA
                      */

                      // define included package locations
                      $GLOBALS["IORCA"]["BASE"]["PATH"] = dirname(__FILE_ _) . "/";

                      function import($classPa th) {
                      // define extension for classes
                      $ext = '.class.php';
                      $errorMessage = '<div style="margin: 10px; padding: 10px; background: Red;
                      color: white; font-weight: normal; font-size: large;"><strong style="color:
                      White">'. $classPath .':</strong> Class doesn\'t exist.</div>';
                      $importFile = str_replace("." , "/", $classPath) . $ext;
                      $path = pathinfo($GLOBA LS["IORCA"]["BASE"]["PATH"] . $importFile);
                      $requirePath = '';
                      if($path['basename'] == "*$ext" && $importDir = opendir($path['dirname'])) {
                      while(false !== ($file = readdir($import Dir))) {
                      if(stristr($fil e, $ext) == $ext) {
                      $requirePath = $path['dirname'] . "/$file";
                      if(file_exists( $requirePath)) require_once($r equirePath);
                      else echo($errorMess age);
                      }
                      }
                      }
                      else {
                      $requirePath = $GLOBALS["IORCA"]["BASE"]["PATH"] . $importFile;
                      if(file_exists( $requirePath)) require_once($r equirePath);
                      else echo($errorMess age);
                      }
                      }

                      ?>


                      --
                      If the Internet is a Marx Brothers movie, and Web, e-mail, and IRC are
                      Groucho, Chico, and Harpo, then Usenet is Zeppo.


                      Comment

                      • Zurab Davitiani

                        #12
                        Re: Flexible __autoload scheme

                        Berislav Lopac wrote:
                        [color=blue]
                        > I am very grateful for your script, as it gave me a great boost when I
                        > created my internal little framework. I'll keep using it even with PHP5,
                        > but I'd still like to make use of __autoload somehow.[/color]

                        Sure, that's what I suggested. You can delegate parts of your script to
                        __autoload instead of doing it manually. Let me elaborate:

                        function __autoload($cla ss_name) {
                        foreach($GLOBAL S["IORCA"]["CLASSPATH"] as $path) {
                        if(file_exists( $path . $class_name . ".php")) {
                        require_once($p ath . $class_name . ".php");
                        break;
                        }
                        }
                        }
                        [color=blue]
                        > function import($classPa th) {
                        > // define extension for classes
                        > $ext = '.class.php';
                        > $errorMessage = '<div style="margin: 10px; padding: 10px; background: Red;
                        > color: white; font-weight: normal; font-size: large;"><strong
                        > style="color: White">'. $classPath .':</strong> Class doesn\'t
                        > exist.</div>'; $importFile = str_replace("." , "/", $classPath) . $ext;
                        > $path = pathinfo($GLOBA LS["IORCA"]["BASE"]["PATH"] . $importFile);
                        > $requirePath = '';
                        > if($path['basename'] == "*$ext" && $importDir = opendir($path['dirname']))
                        > { while(false !== ($file = readdir($import Dir))) {
                        > if(stristr($fil e, $ext) == $ext) {
                        > $requirePath = $path['dirname'] . "/$file";
                        > if(file_exists( $requirePath)) require_once($r equirePath);
                        > else echo($errorMess age);
                        > }
                        > }
                        > }[/color]

                        I think what you are doing here is including every file in the directory
                        with *. What I am suggesting is, instead you add that path to
                        $GLOBALS["IORCA"]["CLASSPATH"][] so you can __autoload() classes from them
                        as necessary.

                        So, if your import statement looks like

                        import("org.act ive-link.xml.*");

                        Then you do not load any classes yet from import function - just add that
                        path to the classpath array and then when you do:

                        $myXML = new XML();

                        the XML class is __autoload() -ed by that function automatically as
                        required.

                        I hope I expressed myself clearer this time and hope this helps.

                        Comment

                        • Berislav Lopac

                          #13
                          Re: Flexible __autoload scheme

                          Zurab Davitiani wrote:[color=blue]
                          > Berislav Lopac wrote:
                          >[color=green]
                          >> I am very grateful for your script, as it gave me a great boost when
                          >> I created my internal little framework. I'll keep using it even with
                          >> PHP5, but I'd still like to make use of __autoload somehow.[/color]
                          >
                          > Sure, that's what I suggested. You can delegate parts of your script
                          > to __autoload instead of doing it manually. Let me elaborate:
                          >
                          > function __autoload($cla ss_name) {
                          > foreach($GLOBAL S["IORCA"]["CLASSPATH"] as $path) {
                          > if(file_exists( $path . $class_name . ".php")) {
                          > require_once($p ath . $class_name . ".php");
                          > break;
                          > }
                          > }
                          > }
                          >[/color]

                          < snip>
                          [color=blue]
                          >
                          > I think what you are doing here is including every file in the
                          > directory with *. What I am suggesting is, instead you add that path
                          > to $GLOBALS["IORCA"]["CLASSPATH"][] so you can __autoload() classes
                          > from them as necessary.
                          >
                          > So, if your import statement looks like
                          >
                          > import("org.act ive-link.xml.*");
                          >
                          > Then you do not load any classes yet from import function - just add
                          > that path to the classpath array and then when you do:
                          >
                          > $myXML = new XML();
                          >
                          > the XML class is __autoload() -ed by that function automatically as
                          > required.
                          >
                          > I hope I expressed myself clearer this time and hope this helps.[/color]

                          Yes, now I see what you mean. Basically, the import function adds the path
                          of a directory instead of including a specific file. This seems interesting,
                          as it forces the user to manually state which packages his class uses,
                          without the need to include specific class, or the entire package even if
                          not all classes are used. This seems quite reasonable and I'll look further
                          into it.

                          I was thinking of making an Autoloader class that whould handle all this, so
                          it could even include several different autoloading policies, chosen when
                          called by the __autoload.

                          A tangential question: does anyone has an idea which would have a better
                          performance -- iterating through an array as you suggest above, or finding
                          in an XML file using XPath and SimpleXML, assuming the same number of nodes?

                          Berislav

                          --
                          If the Internet is a Marx Brothers movie, and Web, e-mail, and IRC are
                          Groucho, Chico, and Harpo, then Usenet is Zeppo.


                          Comment

                          • Zurab Davitiani

                            #14
                            Re: Flexible __autoload scheme

                            Berislav Lopac wrote:
                            [color=blue]
                            > A tangential question: does anyone has an idea which would have a better
                            > performance -- iterating through an array as you suggest above, or finding
                            > in an XML file using XPath and SimpleXML, assuming the same number of
                            > nodes?[/color]

                            What would be the purpose of an XML file if all you want is a
                            one-dimensional classpath array that's created on the fly? What other
                            properties/attributes would you track? Almost certainly, an XML file would
                            need more memory and create more overhead.

                            Comment

                            • Berislav Lopac

                              #15
                              Re: Flexible __autoload scheme

                              Zurab Davitiani wrote:[color=blue]
                              > Berislav Lopac wrote:
                              >[color=green]
                              >> A tangential question: does anyone has an idea which would have a
                              >> better performance -- iterating through an array as you suggest
                              >> above, or finding in an XML file using XPath and SimpleXML, assuming
                              >> the same number of nodes?[/color]
                              >
                              > What would be the purpose of an XML file if all you want is a
                              > one-dimensional classpath array that's created on the fly? What other
                              > properties/attributes would you track? Almost certainly, an XML file
                              > would need more memory and create more overhead.[/color]

                              Because array must be iterated through, while a DOM document can be searched
                              via XPath by a simple /*/classname (or something; I must refresh my Xpath
                              skills). Of course that XML needs more memory, but I'd like to know
                              generally which is faster, iterating arrays or DOM document creation + Xpath
                              search. Intuitively I'd also go for the first, but I'm asking if someone has
                              any first-hand experience.

                              Berislav

                              --
                              If the Internet is a Marx Brothers movie, and Web, e-mail, and IRC are
                              Groucho, Chico, and Harpo, then Usenet is Zeppo.


                              Comment

                              Working...