Over a million developers have joined DZone.

PHP UML generation from a live object graph

DZone's Guide to

PHP UML generation from a live object graph

· Agile Zone ·
Free Resource

Adopting a DevOps practice starts with understanding where you are in the implementation journey. Download the DevOps Transformation Roadmap. Brought to you in partnership with Techtown.

Sometimes you need to share a design with your colleagues. You can walk him through the code, and explain which classes and interfaces you created, but there are higher abstracted models that you can show to him to make him grasp the picture quickly.

One of these tools is UML, and in particular class diagrams. A good class diagram can show the relationships between a dozen of classes, and thus the design of an entire small component.
I'm no advocate of designing software before coding however, since the code is the ultimate design document. When we prepare UML diagrams, we mostly are in the stage after having Test-Driven the code and committed it. The goal is sharing information quickly, and then throw away the diagram when it gets out of sync with the code.


An approach to produce this kind of diagrams is to have one of the members of a pair programming duo draw on paper with a pencil and a rubber. Paper still is the best expressive medium, and pencil allows for easy editing. In some cases, we even update our paper sheet while we were extracting classes during refactoring phase.

Even when you draw Uml it with a computer-based tool, the boring part is drawing the diagram. After all, part of the information is already embedded in the code; and we already know that this diagram will be short-lived, since the code evolves quickly.

So as a proof of concept I started writing a tool, PHP UML Generator, which extracts an Uml class diagram from a PHP object graph, which has been previously instantiated from some factory. It's basic reverse engineering.

Existent tools like Doxygen produce diagrams of this kind, but starting from static analysis of the code, not from a live object graph. This means Umlntrospector would be more difficult to integrate, as you need to bootstrap your application, but I think this is outweighted by two factors:

  • the single source of truth is the object graph: when annotations are outdated or missing, if you have a working test suite the object graph will be in sync with the current state of the code.
  • the solution is simpler: Reflection is used to extract information instead of parsing of docblock comments and code.


Since this is a proof of concept, I tried to build a minimum viable product:

  • by default the introspector produces UML definitions for Yuml.me, used for visualization. Other adapters can be added.
  • The introspector follows composition and inheritance to N levels: class relationships are more important than methods, which are also likely to be too many to show.
  • The introspector does not distinguish between objects of the same class for now (a class diagram is the objective, but they may be more associations, named differently.)
  • It's able to ignore libraries namespaces like Zend_ or Doctrine_.
  • It skips scalar fields as they provide almost no information.
  • It considers base class names and PHP 5.3 namespaces.


With this article I'm validating with the community the idea of analyzing a live object graph. Here are some very small examples of the results produces on PHPUnit objects and a Doctrine 2 Entity Manager with this code (cannot run standalone, it's included just for explanation):

require_once '/home/giorgio/code/pug/tests/bootstrap.php';
require_once '/home/giorgio/code/ddd-talk/bootstrap.php';

class UmlIntrospectorPHPUnitTest extends PHPUnit_Framework_TestCase
    public function testGenerationOfyUMLCode()
        $introspector = new UmlReflector\Introspector;
        $directives = new UmlReflector\Directives;
        $introspector->visualize($this, $directives);

    public function testGenerationOfyUMLCodeOnAPHPUnitMatcher()
        $introspector = new UmlReflector\Introspector;
        $directives = new UmlReflector\Directives;
        $introspector->visualize($this->equalTo(new stdClass), $directives);

    public function testGenerationOfyUMLCodeOnDoctrine2EntityManager()
        $introspector = new UmlReflector\Introspector;
        $directives = new UmlReflector\Directives;
        $em = Test\BaseTestCase::getEm();
        $introspector->visualize($em, $directives);

Here are the pictures obtained by putting the generated directives into yUML (I'll produce also a direct link in the future, but there is a limit of length):




Take Agile to the next level with DevOps. Learn practical tools and techniques in the three-day DevOps Implementation Boot Camp. Brought to you in partnership with Techtown.


Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}