Powerpoint exploring the locations used in television show Time Clash
Os Minnee
1. Ending Rails Envy in PHP5
__call for fun and profit!
Slides with notes at http://www.siverstripe.com/rails-envy/
Who am I? Oooh, a white slide!
Sam Minnée
CTO
SilverStripe Limited
http://www.silverstripe.com
The concepts discussed today have been used extensively
in our BSD-licensed CMS, in production use on around 100
sites.
SilverStripe is a BSD-licensed CMS focused on providing a productive development framework on top
of a CMS that it aimed squarely at content authors, not developers.
http://www.silverstripe.com
It’s relatively new (first open-sourced November 2006) but our developer community is growing well
and we’re always looking for new developers.
2. Why the Envy?
PHP Rails
Productive development
Gets the job done, mostly
platform with lots of cool stuff
The language people love to hate Very trendy
A variety of hosting options Harder to Host
Good NZ government
Too new for government
acceptance (They like OSS!)
Rails was one of the main options I considered when developing SilverStripe. However, there were
other advantages to PHP that trumped it - in short, Rails would cut down our user-base too much.
What to do?
• Use PHP5
• Build frameworks to make it productive, and
maybe even trendy.
We decided to use PHP, but focus on building a productive development framework, a similar goal to
the Rails team.
3. DISCLAIMER
THIS IS NOT A LANGUAGE WAR
I know very little about the details of Rails vs.
what is presented today, in fact, I’m pretty sure
that my understanding of the benefits of using
Rails is pretty naïve.
I just thought the title would be edgy.
Forgive me.
(besides, I still envy Rails. Just a little.)
__call()
The possiblities are endless with this handy little method...
It lets us create “magic methods” are are implicitly defined.
The __call() method of a class will handle any unrecognised method call. Similar methods for
properties, __get() and __set(), can be used to create “magic properties” too.
4. Object-Relational Models
The first use-case
The way that I want it to be:
An ORM is a great way of wrapping access to a database into a nice package. We wanted to add
relationship information to our data classes, and have these accessible by set classes that implement
Iterator, but need more
The code shown in the presentation is criminally oversimplified. In particular, in a real implementation
we would want to use For a more complete implementation, the SilverStripe codebase is a good place
to look.
First Approach
Here we have defined a __call() method on the DataObject that
5. Problems
• __call contains a lot of program-specific
information.
• The if / elseif construct lower performance as
it grows
• Won’t scale well to more kinds of magic
functions.
Second Approach
Map of method handlers
Define methods makes a number of calls to $this->addWrapperMethod(). This is how you define your
magic methods.
6. Second Approach
__call() implemented in Object
The addWrapperMethod() method, and the __call() handler, are defined in a generic Object class.
* addWrapperMethod() adds to Object::$extraMethods
* __call() interrogates Object::$extraMethods to know what to do.
Calling defineMethods
Once per class, not once per object, for performance.
Calling defineMethods() for every object can get really slow. You typically have to instanciate a large
number of DataObjects to generate a single page.
7. Aggregation
Adding Versioning to DataObject
Note: Criminally Oversimplified
This is a very simple illustration of how aggregation might be used to help implement versioning &
staging. In this case, we’ve just used it to add publish() and rollback().
In a real implementation, you need a way of modifying the code for reading/writing DataObjects to
actually change the data model. But that is beyond the scope of this talk.
What can defineMethods do?
• addWrapperMethod(‘Products’, ‘getComponents’);
• addMethodsFrom(‘extensions’, ‘Versioned’);
• Other possible
• BUT: the more we have, the slower things get... So be
careful!
In addition to addWrapperMethod(), it’s worth adding addMethodsFrom()
Performance in the __call() method is crucial because it will be used so often by your application.
8. Adding addMethodsFrom
Step 1: Implement addMethodsFrom() that will be called by defineMethod(). It should add more stu! to
Object::$extraMethods
Adding addMethodsFrom
Step 2: Update __call() to handle the new data that we’ve put into Object::$extraMethods
Note: this isn’t a particularly well optimised sample. Improving on it is left as an exercise for the
reader ;-)
9. Implementing Aggregation
We can now use the addMethodsFrom() methods to implement aggregation, by updating
defineMethods() in the Object class.
Why Bother?
• I’m Lazy
• I’m Picky
• (I like over-engineering?)