[wp-hackers] Coding Standards: Functions vs. Classes

Andrew Nacin wp at andrewnacin.com
Sun Mar 18 20:44:26 UTC 2012


On Sun, Mar 18, 2012 at 3:32 PM, Braydon <ronin at braydon.com> wrote:
>
> Post as a class has more advantages, especially if it were to include all
> template tags for posts. It could be $post->excerpt() instead of
> the_excert() and you know it can only be the except of that post and not
> from the global state of $post. Would be one less point of confusion to not
> stumble on, especially if you're new and haven't yet figured out that the
> global $post is super important.


Don't be surprised if WP_Post happens in 3.5 or 3.6.

We've been experimenting with classes for a few versions now:

 - In 3.1, we introduced list tables, which taught us a lot about how we
should (and should not) approach OO development. Also WP_Tax_Query,
WP_User_Query, WP_Meta_Query (and nearly WP_Object_Query to be an
abstraction of those three plus WP_Query).
 - Also in 3.1, the admin bar code was brought in from WordPress.com. It
was architected as a class originally, and stayed that way.
 - In 3.2, we looked at magic getters to solve some issues with wpdb.
(Didn't pan out.)
 - In 3.3, the admin bar code was largely rewritten, with many pieces now
protected.
 - Also in 3.3, we added methods to the $current_screen object, and
WP_Screen was born.
 - Also in 3.3, WP_User ended up with lazy-loaded properties and some new
internal methods.
 - In 3.4, get_themes() has evolved into WP_Theme (#20103).

Those are a good number of solid examples, and while we started at the
fringe, we're getting closer to major WordPress APIs and old areas of the
codebase. Core is around 175,000 lines of code. Many of those lines are
four, five or more years old. I think the current state of our code churn
is very healthy and at a very good place.

The bump to PHP 5.2 happened with WP 3.2. Even then, we were mainly focused
on removing dead code, rather than focusing on introducing new magic bits.
(Slow and steady wins the race.) Someone mentioned PHP 5.3 namespaces, and
that makes me laugh. In two years, PHP 5.3 adoption (in terms of WordPress
sites) has gone from 4% to 10%. Not holding my breath. [1]

[1]
http://mozillamemes.tumblr.com/post/19415247873/surely-chrome-will-drop-h-264-lets-just-wait

And so, we have the opportunity to use classes to serve a few main purposes:

 - Namespacing. In lieu of formal namespaces, you can use a class to wrap a
bunch of functions, often as a singleton. This is often a plugin pattern.
We've also exhausted much of the good function names (and the bad ones too)
for things like our taxonomy API — it would be nice to use classes if
nothing else than to start fresh and wipe what we have under the rug.

 - Encapsulation and forwards compatibility. We've never quite gotten to
the point where we've found our feet in cement due to backwards
compatibility concerns, but it is very nice to be able to finalize a class
and wrap select pieces in private properties in methods.

 - Backwards compatibility. ArrayAccess, for example, can allow us to
bypass a number of issues when moving from an array to an object, as can
iterators and the full ArrayObject. Magic methods help a lot. We already
pass around lots of stdClass objects (get_post(), get_current_screen(),
get_term()) and moving those to proper objects can be nice.

Of course, this doesn't mean we're going to rewrite the entire codebase
overnight. Rewriting code for the sake of rewriting code is not a good use
of our time. It only makes sense to rewrite code when we bring new
functionality to an area, especially if that new functionality is complex
and would benefit more from a rewrite, than from shoehorning it in.

That also does not mean we're going to use classes everywhere. There are
plenty of situations where procedural code is going to be better. One good
example is to allow for easier barriers to entry (like template tags and
conditional tags). I like classes and objects, but I don't drink the
Kool-Aid.

While it may be "coder's choice" for sets of functions versus classes, just
understand we don't take those decisions lightly, and yes, there is a
careful method to our madness. register_post_type() was 2.9, hence why it
is a simple function that stores everything in a global. I have a feeling
things would be different if it were coded today — but that is *not* a
reason to jump up and go rewrite it.

I am at the point where I will fight hard to prevent any more globals be
added to core; we've been rather good about this for at least a year now.
That said, static class variables (as suggested) aren't exactly any better.
They're not. Don't let anyone who tells you otherwise stand uncorrected.
The benefit is that they let you hide data. The cost is that you are then
hiding data *from yourself*. Global state (a global variable, a static
method, a static property, what have you) is not testable. [2,3,4,5,6] So
there better be a really good benefit for using classes in this case.

[2] http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/
[3] http://misko.hevery.com/2008/08/25/root-cause-of-singletons/
[4] http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/
[5]
http://googletesting.blogspot.com/2008/11/clean-code-talks-global-state-and.html
[6]
http://googletesting.blogspot.com/2008/12/static-methods-are-death-to-testability.html

The health and future direction of the WordPress codebase is an exciting
challenge. The end result is I'm constantly thinking about rewriting (and
not rewriting) code, new architecture, design patterns, unit testing, and
plugin interfaces. We all are.

Nacin


More information about the wp-hackers mailing list