****************************************
*                                      *
*          PEAR Package PHP_UML        *
*                                      *
*               Tutorial               *
*    (Baptiste Autin, 12/05/2008)      *
*                                      *
****************************************


       *** INTRODUCTION ***

PHP_UML is a reverse-engineering tool.

Practically, with PHP_UML, you can feed an UML CASE tool, like Rational Rose or Argouml,
with an UML representation of some existing PHP source code.
This way you get an immediate overview of an application, with all the usual functions of a software design tool,
like class diagrams exportation, refactoring of object-oriented applications, or automatic code generation.

PHP_UML is three parts :

	- It is a PHP parser
	- It is a PHP metamodel, which provides a set of MOF-oriented classes, as well as a parameterized class, in order to build collections	of PHP-MOF program elements
	- It is an XMI code generator (most UML software can import XMI code, this is how you will get the object model of your PHP application into your design tool)

You can use all, or any of these three functions. Don't be afraid
by the second, it is more straightforward than it sounds.

PHP_UML generates a logical view (composed of the packages and classes found),
and a component view (that maps the filesystem that has been scanned).
Other UML elements (artifacts, relations between classes and files, called "manifestations" in UML2) will be available in future releases. 

See "SOFTWARES_TO_USE_WITH_PHP_UML" for an overview of the existing UML softs.


        *** FEATURES ***

- Reads classes, interfaces, inheritance and implementation relations
- Reads properties, class constants, visibility and static attributes
- Reads functions, their parameters, their default values, their types (when stated)
- Reads docblocks : class comments (@package), method comments (@param and @return) and header file comments (@package)
- Understands the new PHP instructions "namespace" and "use"
- Attempts to guess the types of the elements, through their default values
- Generates XMI version 1.3, and version 2.1 (version 2.1 is minimal, profiles are not yet supported)


        *** EXAMPLE ***

$t = new PHP_UML(1);                        // XMI version 1
$t->parseFile('test1.php', 'testClass');    // Parsing of "test.php". The model XMI will be named 'testClass'.
$t->saveXMI('test_example1.xmi');           // We save the result in a file

Check examples/test_to_run.php for more examples.


     *** OVERVIEW OF COMMANDS ***

$t = PHP_UML();

$t->parseFile($file, $model); 
- $file  : file to parse, or array of files to parse
- $model : name of the enclosing XMI model

$t->parseDirectory($directory, $model); 
- $directory : directory path to scan, or array of pathes to scan 
- $model     : name of the enclosing XMI model

$t->generateXMI($version, $encoding);
- $version  : 1 or 2
- $encoding : XML encoding ('iso-8859-1' by default)

$t->saveXMI($filename);
- $filename : stores the resulting XMI into a file

$t->XMI;
- the XMI produced

PHP_UML_Warning::$stack;
- array of (possible) warnings raised during parsing

See also "examples/test_with_api.php" for an example of XMI generation without using the PHP parser.

           *** OPTIONS ***

$t->acceptedExtensions = array('php');		
- Extensions of parsed files

$t->deploymentView = true;			
- If true, each file generates an artifact, each physical folder generates a package, and the whole is stored in a package called "Deployment view".
In UML2-aware tools, a "manifestation" should automatically be created between a class and its corresponding source artifact.

$t->componentView = true;
- If true, a sub-system is created in the root package, containing the whole file system (files as components ; directories as subsystems, or as nested components in UML2)

$t->dollar = true;
- If true, the symbol $ is kept along with the variable names

$t->docblocks = true;		
- If true, docblocks are parsed (@package, @param, @return)

$t->ignoredDirectories = array('tmp');
- Directories to ignore during the scan

      *** PACKAGES ***

* What's a package? *
In UML, a package is just a container. It contains typed elements, or other packages.
"Typed elements" means datatypes, but also - and most often - classes and interfaces.
UML, by itself, does not say how you should name and organize your packages - this is your business - but it is likely that you will define
them according to logical rules. For example, in PHP_UML, the classes responsible for XMI generation are gathered in a package
called "XMI", while the PHP parser is put into a different package.
No matter the filesystem, which is a very different topic.


* Dependencies *
A dependency between two packages A and B can arise because, for example, 
inside a class belonging to A, an object of a class belonging to package B is created.

Generally, in a given program, you will want to minimize the number of dependencies between the packages,
especially if those dependencies are bidirectional, or if they form circular references.

For example, A->B->C->A (pkg A depends from pkg B, which depends from pkg C, which depends from pkg A) is not a good package design.
But A->B->C (pkg A depends from B, which depends from C) is a common package design.

It should be noted that the latter design means that you can deploy the package C **alone**, without A and B.
This is an important point in reusable software development: the packages that form the top of a package diagram (that is to say, the least dependant ones)
are the best candidates to be reused in other contexts.


* Packages, namespaces and PHP *
Thus, the package is an important concept of object-oriented programming:
 1. It helps to organize the classes in an large application, as their number grows
 2. It allows for better reuse and maintainability of the code.

Unfortunately, for some strange reasons, PHP still does not offer any form of package management.
A framework like PEAR had even to develop from scratch its own system of packages, while many other languages offer natively such a feature.

From version 5.3, PHP has introduced the concept of "namespace", which is intended to avoid name conflicts between classes.
This is clearly not enough for achieving packages, but it is a first step.
Why is it similar?
Because a package is a namespace for its members. Inside an model, two classes can share the same name,
provided that they live in separate packages. You can refer to them by prefixing their name with their nesting packages, like Java does in dotted style:
java.io.File

* And why is it not the same at all? *
In UML, a package can have a URI, a universal resource identifier. There is some good logic to that: when you get a package named "DateTime",
you don't want it to enter in conflict with another package of the same name...

To enforce such unicity in a development environment, one possible way is to match the packages with the filesystem folders, and to put the nested classes into the contained files.
This is not ideal, but it is better than no rule at all, and by using hostames (like org.apache.xalan etc....) for the first packages of the hierarchy, you also lower the risk of collision.

Another possibility is to implement a specific relationship (sometimes called manifest) between the source files and the logical program elements (like packages and classes). This is how .NET procedes, with its "assemblies".

In both implementations, the compiler knows where to reach all the classes of a given package.

Namespaces offer nothing of the kind. They are just qualifying names for interfaces and classes.
One can always "mentally" map the components of a namespace (A::B::C) to some package hierarchy (A, B, C),
but then every class can claim that it belongs to this or that "package": without a specific implementation,
the compiler has not way to determine if the class tells the truth or not.


* Ok, ok, and what about PHP_UML? *
Since packages are so important in UML, PHP_UML tries to use them as much as it can.

First, PHP_UML can read docblocks. So you can specify the package of a class by inserting a "@package Foo" in the class comment.
It can also read file docblocks. So all the classes defined in a file where the main docblock contains a "@package Foo" will be considered as belonging to the package "Foo".
Then, PHP_UML interprets the new namespacing instructions of PHP: "namespace" and "use".
The rule is simple: once it has parsed something like, say, "namespace PEAR::PHP::PHP_UML", PHP_UML considers every further class as belonging to a package called "PHP_UML", that
belongs to a package called "PHP", that belongs itself to a package called "PEAR".
In other words, "::" is considered as a package delimiter in a namespace.

And what about classes that are not docblock-commented and that are not preceded by a "namespace" instruction?
They are simply put into the "default" (or root) package of the UML model.


* Last thing to know about packages... *
Ok, PHP_UML can divide the classes into different packages, if specified.
But how do you refer to the packaged classes (or interfaces) within other packaged classes?
This is a delicate question. PHP_UML does not parse the "require" or "include" instructions, and this might lead to unwanted results.
Take that class:

/**
 * @package A
 */
Class Foo
{
    function foo(Foobar $x) {
    }
}

And here's Foobar:

/**
 * @package B
 */
Class Foobar() {
}

Since it is defined in B, Foobar cannot be reached from context A... unless foo() is modified in:
    function foo(B::Foobar $x) {
    }
... but that writing is only allowed in namespaced PHP.

A workaround should be available in a later release of PHP_UML (by defining some "default" packages where PHP_UML will look into,
each time an unnamespaced classes must be resolved).


* Priority rules in PHP_UML *

Finally, here are the priority rules, regarding package definition:
 1. Package specified in a "namespace" instruction (overrides everything)
 2. Package defined in a class comment
 3. Package defined in a file docblock (top of page, before every PHP instruction)
 4. Package specified in parseDirectory/parseFile($directory, $model, $package)
 5. Package by default (in the root package)


       *** XMI COMPATIBILITY ***
        
The XMI/UML dialects are not easy to decipher (XMI and UML are two different standards), and so your XMI code might be interpreted differently by the modelling tool you are going to use along with PHP_UML.
This is particularly true for the version 2 of XMI.
For instance, the Eclipse plug-in "EMF - UML" only accepts a particular flavour of XMI, called "ecore",
which is partly compatible with the one you'll get with PHP_UML.

PHP_UML does not aim at implementing the whole UML specification, but instead it is designed to reverse-engineer PHP to UML, in a quick and simple way.

Read the file: SOFTWARES_TO_USE_WITH_PHP_UML, for more information on compatible soft.


