Support for class loading from class archives in the core

  Status: implemented,  Fri Oct 13 19:23:21 CEST 2006
  • Created: 2006-09-15 10:11:39+0200
  • Categories: <core>
  • Author: kiesel

Scope of Change

Support for class loading and bootstrap class loading will be added to the core.

An application should be contained in a class archive so you only need to supply lang.base.php and the archive file.

The package io.cca will be moved into the core package lang and be renamed to lang.archive. An ArchiveClassLoader will be available after bootstrapping has finished.


Rationale

Deploying and maintaining an application can currently be done in two ways.

Subversion repository

Checkout the complete XP framework from the Subversion repository and updating the tree with Subversion update mechanism. Tags have been created to achieve software consistency, but that also increased maintainance overhead. This approach required a recent version of Subversion installed on the system and network connectivity to the Subversion server.

Tarball repository

Unpacking a tar archive from an XP framework release, creating a full source code tree in the target directory. While this reduces software requirements to a "tar" installation, no simple update mechanism exists.

To simplify shipment of applications written in XP, loading classes from archives should be supported transparently by the uses() core method.

Functionality

uses() will be changed to transparently support loading from class archives. Support will include bootstrap loading, which means that it cannot rely on any XP core classes being available at loading time.

The class loading algorithm

When a class should be loaded, each part of the include_path will be checked, if it can provide the class to load depending on its own type.

Directory include_path parts

Include_path parts which reference directories serve as base directory and uses() tries to load the class to load it from the file relative to the directory.

File include_path parts

Parts that reference files will be treated as class archives. Uses() scrutinizes whether the archive provides the class and loads it from there if it can. If the file is no class archive, a fatal error will be raised.

If one part cannot provide a class, the next include_path part is being checked. If all parts were unable to provide the class, a fatal error is raised.

ClassLoaders

A class which has been loaded by an ArchiveClassLoader will be associated with the loading classloader by the mechanism described in rfc://0071.

Loading resources

Whenever a class loads other files "from the filesystem", relative to its own location, it must use its associated classloader to fetch it. Ignoring this rule cannot be detected but will lead to breakage of the class when used after being loaded out of an archive.

The deprecated resource loading mechanism is:

  // Package net.xp_framework.rfc
class Foo extends Object {
function __construct() {
$file= &new File(dirname(__FILE__).'/META-INF/mysettings.ini');
$file->open(...);
// ...
}
}

The new resource loading mechanism is:

  // Package net.xp_framework.rfc
class Foo extends Object {
function __construct() {
$class= &$this->getClass();
$cl= &$class->getClassLoader();

// Resource path must reflect the package name to conform with
// above example
$bytes= $cl->getResource('net/xp_framework/rfc/META-INF/mysettings.ini');
// ...
}
}



Security considerations

n/a

Speed impact

This change implies both a speed loss and a speed gain. In addition to that at minimum two new classes will have to be added to the core of the framework and be loaded at every startup.

Speed loss

Class archives start with a header which contains metadata information about all contained files. As the header must be fully read to acquire information about the archive, and the header size grows for each added file, big archives will be slightly slower than small archives.

Speed gain

As the archive file only needs to be opened once, several stat() system calls will vanish, speeding up the loading process as a trade-off for the initially mentioned speed loss.

Dependencies

n/a

Related documents

- http://xp-framework.net/rfc/contrib/rfc0074.diff Patch implementing this RFC

- http://experiments.xp-framework.net/?people,kiesel,php,cca/package.php Package creation utility

Comments

- kiesel, Tue Sep 19 11:53:28 CEST 2006 Currently, the classloader distinguished only between directories in the path and files in the path. Files will be treated as archives. To keep the option to have multiple different file formats later, we need to agree on a "standard" XP archive filename extension. There are several proposals: . .cca (as the package name) . .xar (XP archive) . .xpa (XP archive, proposed by George Aprozeanu) . .xpm (XP module, proposed by George Aprozeanu) . .xpar (XP Archive)

- kiesel, Tue Sep 19 13:35:06 CEST 2006 Initial patch made available, still containing a lot of debug.

- kiesel, Tue Sep 19 14:45:49 CEST 2006 Should the include_path be resetted to an empty one after uses() has initialized its paths? This could speed up include() calls.

- kiesel, Wed Oct 4 14:34:49 CEST 2006 These are some timings from a testrun (all tests were run multiple times to make cache play less a role): Run #1: Old lang.base.php behaviour ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  alex@lost:~/devel/xp.clean# time php 
    -dinclude_path=.:/home/alex/devel/xp.clean/ 
    ../../uses.php 

  21 classes loaded.
  111 classes loaded.

  real    0m0.199s
  user    0m0.128s
  sys     0m0.051s
  

Run #2: New implementation with only directory-includes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  alex@lost:~/devel/xp.public/trunk/skeleton# time php 
    -dinclude_path=.:/home/alex/devel/xp.public/trunk/skeleton 
    ~/uses.php 

  21 classes loaded.
  113 classes loaded.

  real    0m0.209s
  user    0m0.150s
  sys     0m0.038s
  

Run #3: New implementation, all classes loaded from archive ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  alex@lost:~/devel/xp.public/trunk/experiments/people/kiesel/php/cca# time php 
    -dinclude_path=public.xar:. 
    ~/uses.php 

  21 classes loaded.
  113 classes loaded.

  real    0m0.224s
  user    0m0.177s
  sys     0m0.025s
  

- kiesel, Mon Oct 9 16:41:10 CEST 2006 Loading classes/resources would be done by checking the invocation path of the current scope (with debug_backtrace()) and then using the associated classloader of the class. Shouldn't the resource loading just iterator over the default include_path and use the appropriate loader?

<EOF>


Table of contents