Advertisement

Object-Oriented Programming in WordPress - Inheritance II

by

In the previous article, we introduced the concept of object-oriented inheritance, attempted to place it laymen's terms, and then also took a high-level look at the conceptual model of how it works within the context of programming.

But before we go any further and/or if you're just joining in the series, please review everything we've covered thus far by reading the previous articles:

  1. An Introduction
  2. Classes
  3. Types
  4. Control Structures: Conditional Statements
  5. Control Structures: Loops
  6. Functions and Attributes
  7. Scope
  8. Building the Plugin I
  9. Building the Plugin II
  10. Document the Plugin I
  11. Document the Plugin II
  12. Inheritance I

Yes - we've covered a lot, but in order to lay the foundation for a beginner to have a strong place from which to start writing object-oriented PHP, there's a lot to examine.

With that said, inheritance is where we begin getting into the intermediate topics of the paradigm, so this will be the final article that provides a look at the beginner concepts after which we'll end the series with a summary post.

Inheritance Reviewed

Recall that we defined inheritance as the following:

Inheritance is when one class serves as the parent class for a child class that provides a number of attributes and methods common to both the parent and child; however, the child as the ability to introduce it's own attributes.

It's a bit less formal than what you may find in an academic book, or even on Wikipedia, but it still explains the idea in terms that illustrate the point.

In this article, we'll review all of the necessary code, functions, and reserved words related to the topic, we're going to take a look at how we can implement it within PHP in a very, very simple platform-agnostic way,  and then we'll review an actual implementation of where inheritance is at play within WordPress.

So with that set as our roadmap for the article, let's go ahead and get started.

PHP Facilities

In order to implement inheritance in object-oriented PHP, there are a number of reserved words with which we need to familiarize ourselves. Luckily, most of the words we've already covered, and those that we haven't are clear enough such that it's easy to remember them.

So before we dive into looking at code, let's take a look at all of the reserved words in the language that we need to know so that we can begin to actually get into creating something.

  • extends is reserved word that indicates that one class is the child of another class. For example, in our previous article, a Post extends Content. We'll see this in play soon.
  • private is an attribute that is applied to properties and functions that mean they are accessible only within the context of the class in which they are defined.
  • protected is similar to private with the exception that the properties and methods that are marked as such can be accessed by the given class and any child classes.
  • public is the opposite of private in that it means any class - the given class, a subclass, or a third-party class - can access the property or method in order to change it's information or call the function.

You also need to be familiar with the :: operator, but we'll cover that a little bit later in the article when we begin looking at code.

And that's it - nothing terribly daunting, is it? And what's even better is that if you've been following along with us throughout this series, then you're likely familiar with every word save for extends.

Anyway, with that said, let's start working on an example.

Some Example Code

In order to get started writing some example code, we need to lay out exactly what it is that we're going to be trying to model (after all, that's what code does, isn't it?). 

In keeping consistent with the theme used throughout this series - especially in the last article - we'll have a parent class called Content, and two child classes each of which will be named Comment and Post, respectively.

This will allow us to see how properties and methods exist within a single class, and how children can access attributes of their parents, as well as how parents can protect their properties and functions from their children, as well.

But implementation will demonstrate far more than talking about it, so let's started writing some code.

The Parent Class

In our example, the parent class is going to be the Content because both of the subclasses - that is, the Post and the Comment - are types of content that have unique information associated with them that is not specific to the Content class.

The key to inheritance is to identify all of the properties and methods that are common across all of the classes and keep them defined in the parent class or, in our class, in Content.

Though this can vary based on how you view this, we'll setup Content such that it includes:

  • a date on which the content was published
  • an author 
  • a method for saving the content
  • a method for formatting the content
  • a method for retrieving the content
  • and a method for retrieving the content author 

First, we'll look at the code, then we'll explain everything that's going on with it.

<?php

class Content {

    protected $publish_date;

	protected $author;

	private $content;

	public function __construct() {

		date_default_timezone_set( 'GMT' );
		$date = new DateTime();

		$this->publish_date = $date->format( 'Y-m-d H:i:s' );
		$this->author = '';

	}

	public function save( $author, $content ) {

		$this->author = $author;
		$this->content = $this->format_content( $content );
		$this->content;

	}

	public function read() {
		return $this->content;
	}

	private function format_content( $content ) {
		return strip_tags( stripslashes( $content ) );
	}

	public function get_author() {
		return $this->author;
	}

}

As previously mentioned, we have two protected attributes and a private attribute. Recall that this means that all of the subclasses can access the $publish_date and the $author, but only the Content can access the $content attribute.

Also note that much of the code that you see in the above class is basic object-oriented PHP. There's nothing that stands out that deals directly with inheritance other than some of the access modifiers that we've declared. That is to say that it's relatively common to code we've seen thus far in this tutorial.

One of the things that's worth noting is that the private function is in place to demonstrate two things:

  1. How private functions are only accessible within the context of the class in which its defined.
  2. Strips any tags and slashes from the content so that markup cannot be saved with the content.

Of course, this code isn't connected a database or a file system or anything, but the point still remains.

Note that, in the code above there are a couple of things that we've needed to add in order to satisfy PHP's requirements. They are beyond the scope of this article, but it's worth pointing out here:

  • The code to date_default_time_set is required to set the timezone off of which the time can be retrieved.
  • The constructor is responsible for initially setting the publish date of the content, and it initializes the author property to an empty string. This is so that a Post can have its own author and the Comment can have its own author, as well. As we'll see later, a Comment can even override the default publish date.

Note also that we're able to retrieve the content from the read method and we're able to get the author from the get_author function.

The First Child

Next, let's go ahead and create the Post subclass. First, we'll take a look at the code and then we'll see how it interacts with the Content class we just created.

<?php

class Post extends Content {

    public function __construct() {

        parent::__construct();
        $this->author = 'Tom McFarlin';

    }

    public function post( $content ) {
        $this->format_content( $content );
    }

}

The class appears small, right? There are no properties - because it inherits them from the Content class - and there are only two functions, one of which is unique to the class - post.

Notice that in the constructor, we first make a call to the parent constructor using the :: operator. You can read much more about this in the manual, but suffice it to say that the operator is reserved to reference a number of difference things outside of the class in which it is defined. In our case, that's the call to the parent's constructor.

Next, I've opted to set my name as the author of the post. Notice that I'm using the $this keyword. Because the subclass inherits properties from its parent, it can refer to those properties and if they were defined within itself.

Note that this is possible not just because Post extends Content but because the property is marked as protected in Content, as well. If it were marked as private, this would not be possible.

The Second Child

Now that we've created the Post class, we also have the Comment class which, recall, represents someone leaving a a comment on a post. Were this production-level code, there would be far more code: We would need to relate a comment to a post, determine if a comment is a reply to an existing comment, mark a status of a comment, and so on.

But for the purposes of demonstrating inheritance, we're leaving all of that out and focusing only on the things that can drive the concepts.

<?php

class Comment extends Content {

    public function __construct() {
        parent::__construct();
    }

    public function add( $comment ) {
        $this->save( 'John Doe', $comment );
    }

}

As you can see, the Comment code isn't much different from the Post code. To a degree - this is good because it shows that we've abstracted the proper parts into our base class. 

Anyway, notice that after we construct the Comment, we make our call to the parent constructor. Next, we define the add method which is responsible for taking the incoming comment and then saving it by passing the comment author and it's content to the save method.

The nice thing is that the save method is already defined within the base class which also handles all of the formatting through the use of a private function, so we gain that functionality as we create our child class.

Working with The Example

With that done, let's run a couple of examples to show how the pieces fit together. To make sure this code executes, all you need is a web server, a directory out of which to run PHP scripts, and a text editor.

First, we'll create an instance of Content and then we'll call a debug statement so that we can see what constitutes an instance of the class.

$content = new Content();
var_dump( $content );

Permitting all works correctly, you should see everything that's above.

Next up, let's go ahead and create a post. Since we're setting all of the information in the context of the class, all we really need to do is call a function on the class in order to display the information.

For example:

$post = new Post();
echo 'The post author is: ' . $post->get_author();

Again, since we've set everything up in the code itself, simply calling the method demonstrates the concept.

Finally, we can create a Comment, call the add method on an instance of the class, attempt to pass in malicious code (only to see it stripped out by our code). If everything goes well, you should see the following:

$comment = new Comment();
$comment->add( '<script type="text/javascript">alert("This is my comment.");</script>' );
echo 'The comment reads: ' . $comment->read();

And that's it: Our simple demonstration of inheritance.

Inheritance in WordPress

When it comes to looking at inheritance in WordPress, the very first thing that comes to mind for myself - and likely other developers - is the Widgets API. The reason I say this is because the API is powered by inheritance.

Sure, widgets can be created without using the API, but I'd argue that's a misstep in development. Why make things more complicated for yourself when there's already a foundation in place to do it? But I digress.

The nice thing about this particular API is that it showcases all of the high-points of object-oriented programming and inheritance at work. For example, here's a piece of sample code taken directly from the Codex:

<?php

class My_Widget extends WP_Widget {

        /**
         * Sets up the widgets name etc
         */
	public function __construct() {
		// widget actual processes
	}

	/**
	 * Outputs the content of the widget
	 *
	 * @param array $args
	 * @param array $instance
	 */
	public function widget( $args, $instance ) {
		// outputs the content of the widget
	}

	/**
	 * Outputs the options form on admin
	 *
	 * @param array $instance The widget options
	 */
	public function form( $instance ) {
		// outputs the options form on admin
	}

	/**
	 * Processing widget options on save
	 *
	 * @param array $new_instance The new options
	 * @param array $old_instance The previous options
	 */
	public function update( $new_instance, $old_instance ) {
		// processes widget options to be saved
	}
}

Now that we've covered the conceptual model, looked at the keywords and methodology, written our own code, and created our own example, this should be relatively easy to follow.

But here's the thing: One of the best ways to get better at writing any type of code is to continually practice the concepts. That is, to explore the ideas written by other people who have done more advanced things that you in prior work.

Case in point, take a look at the first example provided in the WordPress Codex. And if you're working with a later version of PHP that supports features such as namespaces (a slightly more advanced topic), then check out the second example, as well.

The more you review the code and tease it apart, the more you are to learn about it. But going any further than that in this article will take us out of scope of the entire series.

To The End

At this point, we've covered all of the beginner material necessary to lay the foundation for a beginner's guide to writing object-oriented PHP. In the final article, we'll provide a summary of everything we've covered so that we have a single reference for the big ideas that can be bookmarked, saved, or referred to later.

Additionally, we'll have a short period of discussion on a follow-up series, but we'll save that until then.

For now, if you have any questions, comments, and/or feedback on the content, code, or examples above, feel free to do so in the comment section below.

Advertisement