A Complete Guide to Object-Oriented PHP for WordPress Developers

One of the boogeymen that frighten a lot of newer WordPress developers are “objects” and object-oriented PHP. You kind of get it, you aspire to get it, but you just don’t really understand where any of this code comes from or leads. If that’s the case for you, stop and stay awhile. I’ll be going on at length but I feel pretty sure you’ll get a lot from this.

What’s an Object?

I think understanding object-oriented programming must start from an understanding of objects, generally. The entire pattern builds from the realization that we human relate to objects most of the times, not primitives like colors and movements. We see “lion running towards me” not “smear of yellow moving in a southward direction.” This is vital to our survival in more primitive circumstances. And I know it feels abstract from a discussion of programming, but understanding the abstraction correctly is essential if you want to get the most you can out of object-oriented code.

An object is an amalgamation of properties and behaviors. Without thinking about it, when entering a new room, my brain reports things like “chair”, “person”, “dog”, “carpet”, “wall.” If you think about this from the level that our eyes, ears, etc understand, this is a great miracle. Our brains just casually do this, and it’s one of the most profound speed bumps that we humans have had in trying to teach computers to think and work like us.

Humans have this amazing superpower of conceptualization that is so remarkable we don’t even realize it exists. If you tried to lay out the visual phenomena that allow you to classify some things as “chairs” and other things as “not chairs”, you really wouldn’t even know where to start. Is it about size? Not really. Color? Certainly Not. I could go one, but will spare us both.

What’s Object-Oriented Programming?

OOP gives us the ability to usefully group together a set of properties and behaviors into an entity, or “object”

We must appreciate that object-oriented programming (often abbreviated as “OOP”, to be a slightly less-awkward mouthful) builds on this super power. The core thing that “procedural” code lacks that OOP gives us is the ability to usefully group together a set of properties and behaviors into an entity, or “object”, that we find it a little easier to think about.

This allows us to have a “User” object in a programming system, as opposed to a unique identifier we need to remember comes from a specific “user account.” It also allows us to get more complex, and define things like a “View Object” which has specific properties that we’re able to think about and expect across a variety of project technologies and languages.

How Classes Relate to Objects

For most languages, PHP included, the basis of object-oriented programming is actually a “class.” A “class” in an OOP language like PHP is something akin to the telos (for the Aristotelians in the room), or ideal form of an object. More prosaically (but usefully) you could also think of a “class” in OOP as a blueprint. It has the basic explanation of what will go on in the living object, but is both conceptually and practically unique from it.

In PHP, you (90+% of the time) write classes but then work with objects. The process by which this transition occurs is the new keyword. So in PHP, I create a new object with the command new Classname (where “Classname” is the label I gave the class I defined). We’ll get into a bit more detail about this transition in a second, but for know just realize that the transition where I go from a class I wrote to an object I interact with is important.

What’s an Instance?

When we use the new keyword in PHP, we’re “instantiating” the object. We create a new “instance” of it.

For almost all circumstances in PHP, you can think of something like “a dog” as the class, and you’d have a specific instance. These instances would be like my dog Fido and another which is “Suzy Q”, the dog I pet every time I take a walk.

Instances can have specific ways in which they vary, but like dogs they generally behave in fairly similar ways. All dogs bark, but their volume varies. All dogs have fur, but the color and length varies (all the way down to “hairless”). All dogs can run and walk, but the specific speed of each varies.

So Suzy Q is a black dog, with 1cm long hair, who runs at 10km/hr. And Fido is a brown-and-white dog with 3cm long hair, who runs at 8km/hr. Both dogs can run, walk, or bark.

Properties and Methods

In the last paragraph, I said that Suzy Q is black. The $color property for the Dog instance named Suzy Q is black. Similarly, the $color property of Fido is brown-and-white. Just as with dogs, these properties of objects can, sometimes, change over their lifetime. Most dogs get slower in old age, and that’d be reflected in their speed property decrementing over time.

Similarly, dogs can bark. We think of this as a method on the object. Unlike properties, methods do not change between different instances of a class, nor do they change over the life-cycle of an object. If you’ve written enough PHP to have seen the word, PHP object methods are essentially just functions on the object’s class.

Similarly, “properties” is a fancy name for an object’s internal variables. How internal they are is something we’ll talk about in a second. In all cases, though, both the properties and methods are similar to what you’ve seen before with PHP functions and variables, but with one important difference.

The $this keyword, and arrows

When referring to an object’s properties or methods, you’ll always use an arrow (->) in PHP. So if I have a $dog instance floating around, I call it’s bark method as $dog->bark(). If I want to reach its color, I find that at $dog->color. This is what differentiates properties and methods from variables and functions. (Object are simply bags which hold our variables and functions together into more coherent and useful units.)

If you’re outside of an object, you say something like $object->method(). But if you’re inside of the object, say in its freak_out method, how to access its bark method? That’s where the $this keyword (or magic variable) comes in in PHP.

If I’m inside of my Dog classes’ bark method, and I want to refer to my dog’s volume property, I do that with $this->volume. You’ll notice a slightly annoying inconsistencies in PHP here: property declarations have a $ before them, $volume. In use (either inside or outside an object) they don’t.

Privacy — Private vs Protected vs Public

Sometime, you’ll want your methods and properties to only be accessible by you on the inside of your class ($this calls, but not $object ones). You’d do this for reasons like methods that are useful for what you want to do publicly and don’t want to repeat, but which an outsider would never have use for.

To do this in PHP, you’d declare the property private when you declare it. That looks a bit like:

class MyClass {
    private $property;
}

It’s not required in PHP, but useful and highly recommended, to explicitly declare a class’s properties at the top of it. If you don’t, PHP still works. And if you don’t declare whether a property is private, it defaults to public.

For everything we’ve covered so far, both properties and methods can be public or private. And in both cases, that keyword just goes before the line declaring it. There is, as we’ll detail in a bit, a third privacy status in PHP, protected. We’ll discuss what’s that is for under the “Subclasses” section below, where it makes a little more sense.

Pause — Let’s See All of That in Code

So far I’ve run through all this stuff without much code that shows off the ideas. I want to take a second to do that so you have some sense how all of this hangs together when you write it. So this has most of the vital details we’ve discussed before:

class Dog {
    public $color;
    private $volume;

    public function bark() {
        text_to_speech("arf", $this->volume);
    }
}

$fido = new Dog;
$fido->color = 'brown';
echo $fido->color;
$fido->bark();

In line one we declare our class. You’ll notice that the class name starts with a capital letter, this is customary (to better tell between classes and functions) but is not required. It is also customary in the WordPress ecosystem to separate multiple-word class names with underscores. So My_ManyWord_Class. This is less common outside of WordPress, where CapWords (without the underscores) is more conventional.

On the next two lines we declare the properties color and volume, marking them public and private respectively. Finally, we define a public bark method, which uses a theoretical text_to_speech function (you’ll find that in neither PHP or WordPress) which uses that volume property as the second argument.

That ends the class definition. Then we make an instance of our Dog class, $fido. We set Fido’s color to brown and then echo that value. Finally, we call the public bark() method on the $fido object, again an instance of our Dog class.

Magic Methods

Picking back up the theory, something we can’t skip is what PHP calls “magic methods.” These are, as the name suggests, methods with a special thing added on. The “magic” to these methods is that PHP will call them automatically in certain circumstances.

There are a number of magic methods in PHP, but the only one I consider unavoidable for a WordPress developer is __construct. That’s two underscores, followed by the word “construct.” This method’s naming is what identifies it as a magic method. One underscore doesn’t work, neither do three, nor a similar word like “build.”

The __construct magic method is the one that PHP calls (if it’s defined) automatically when someone news your object (instantiates it). So in the example above, if our Dog class had had a __construct method defined, it would have been called automatically. This could have been used if every new dog was supposed to have a color.

The other thing is that when you instantiate an object, you may want to have arguments you pass to that __construct method, you do that in the way you might guess: new Dog('brown'); would work well with a constructor like:

class Dog {
    public $color;

    public function __construct($color) {
        $this->color = $color;
    }
}

$spot = new Dog('black');

So the arguments you pass in new ClassName($arg1, $arg2) go pretty directly to your __construct magic methods as $arg1, $arg2.

What and Why of Subclasses

Another conceptual thing that matters for WordPress — most obviously for widgets — is called “subclassing” or “object extension.” These seemingly opposed terms mean the same thing, and they point to when you borrow some of the properties and behaviors of a parent object, but override certain others.

Given our Dog class, we can think of something like Dachshund as a subclass. For, say, a height property, rather than a default of 10 (arbitrary units), we’d expect a dachshund to have something like 5. That would look like.

class Dog {
    public $height = 10;
}
class Dachshund extends Dog {
    public $height = 5;
}

For this case, the bark method (unshown) of Dog is automatically found on the Dachshund class as well, because that exclass “extended” the Dog one. We’d also automatically get other (unshown here) default properties, magic methods, etc. Anything you don’t explicitly override when you extends or subclass something is automatically the same on that subclass.

Where protected property privacy comes in

I mentioned, in the “Privacy” section above that in addition to the kind-of-obvious public and private protection types, there’s also the protected one. This protected method and property keyword is all about object-extension.

When you declare a property public, anyone can change it. When you declare a property private, no one but that object itself can change it, not even sub-classes. When you declare a property protected, subclasses can change it, but the world cannot access it.

People often recommend that you make things “private by default.” What they mean is that you should default to properties and methods being private, only making them protected or public when a need later becomes clear. This article is far too broad to get into that topic in more depth, unfortunately.

WordPress and Object-Oriented PHP

As a work-a-day WordPress programmer, there are a few places that you’ll likely encounter object-oriented PHP. This first and most common is WP_Query. WP_Query is the very-useful way you can get a new set of posts (that is, any content type, like pages, posts, etc) from the database.

The other way you can’t really avoid it is if you’re making WordPress widgets. When making widgets, you subclass (extends a WP_Widget class), overriding specific methods.

It’s also the case that many things that WordPress functions return are objects under the hood. The $post global, that the_title, etc access is an object. You can also find user objects and more as query results. For this you’ll mostly just want to understand property access, like $user->ID, as you’ll not really be writing or overriding those objects yourself in most cases.

So, is a plugin, like, one object?

Another place you’ll see WordPress developers apply OOP regularly is in plugin development. (Because of the nature of WordPress themes, and their reliance on the template hierarchy, you’ll not really use it much there.)

We can’t go into exhaustive detail here about OOP for WordPress plugins. But generally you’ll see plugins either orchestrating many objects, or just making one single object which contains all the plugin’s behavior. I think there are good and bad reasons that one should use an object or many objects when developing a WordPress plugin. To the good, I think OOP done correctly is a great thing. To the bad, I think OOP done because you think it’s the “right way” and don’t understand how it’s meant to help adds confusion and little value.

In general, you should probably define one or many objects if you have a WordPress plugin of more than ~100 lines of code. It’s just a better way to go. But it’s important to think critically about what those object are and do.

Using WordPress Hooks with Objects

One common pattern inside of OO PHP in WordPress plugins that I find really annoying, however, is an over-WordPressed constructor. WordPress plugins require the use of hooks—actions and filters—to interact with WordPress. Putting them in the constructor of your object chains your object to WordPress, makes it hard to override and tests on isolation the things it does, and generally just doesn’t make sense to me.

I think it’s far better to expose an object’s public methods, and have a bit of imperative/procedural code outside of the object that hooks them in. That way, you can still new up the object, for TDD or other testing, without loading all of WordPress as well. Again, because this article is already on pace for nearly 3000 words I’ll end my discussion of this here.

Beyond: Namespaces, Autoloading, Traits, etc

There’s a lot of stuff I explicitly decided against covering in the this article. Stuff that is really good to know about, really powerful in general in object-oriented PHP, but not specifically relevant or commonly used in the WordPress ecosystem. To put a tiny amount of detail on that, here’s a short list of things you might want to go learn about:

  • Interfaces are a way that you can define “contracts” that many concrete objects could satisfy. They’re really useful for extensibility.
  • Abstract classes, similar to interfaces, are a set of policies that objects may need to adhere to.
  • Final classes are ones which are explicitly un-subclass-able.
  • Static classes, class methods, or properties are ones that are true for all instances (and all method-calls without an instance) on a specific class (of objects).
  • PHP Namespaces are a great way to make it more clear the lineage and ownership of an object.
  • Autoloading let you load up multiple classes without loading them all up explicitly. It underlies the super-useful (but also uncommon in WordPress) dependency-management tool Composer.
  • Traits are bit like sub-objects, where you can define three common methods (for example) and make all objects that include that trait have those methods.

There are surely things relevant to object-oriented PHP which are neither in this article of my list above. If you’re curious about one please leave me a line. I’d love to have this article (in future versions) answer all questions you have.

OOP and WordPress — A Great Match

WordPress is a very old software project. (It is very young relative to human history, of course.) As such, a lot of it was written by people who weren’t totally sold on object-oriented PHP, or before OOP in PHP became the de facto standard. As such, a lot of code in WordPress is not itself very object-oriented.

But for custom plugins, there’s nothing stopping you from writing all the OO code you’d like, because WordPress is wisely unopinionated about that code. It’s also useful, even if you write basic procedural functions and not objects, to understand what the object-oriented code you will encounter actually does. I hope this has been helpful!

Image credit: Wikimedia


2 Responses

Comments

  • Christian Saborio says:

    I have just started working with OOP in WordPress and only wish I had started doing so a lot sooner. I’m revisiting most of the spaghetti code I had written and making classes from it. Makes it so much easier to use, understand, and test!

    Your article is beautifully written and makes absolute sense – keep up the amazing work! :-)

  • John Dee says:

    Great intro to OOP. Another really important reason to be doing OOP in WordPress is to make your code testable. WordPress is eating the internet. It’s high time WP devs learn basic development and software skills. The platform and the user base is just WAITING for you to make something great! wp-bdd.com

Add a comment

(required)

(required)

(optional)