thekid/rfc — Issue #74: RFC 0074: Support for class loading from class archives in the core
Author: thekid
Created: 2011-10-09 14:53:25+00:00
State: open
Labels: rfc

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:

```php
open(...);
// ...
}
}
?>
```

The new resource loading mechanism is:

```php
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?