In continuing our discussion of object-oriented programming in WordPress, we need to begin talking about the idea of scope. In short, this refers to the idea as to classes can control how their attributes and functions are accessed (or whether or not they can even be accessed).
This is yet another core idea of object-oriented programming after which we should be in good shape to begin working on an actual WordPress plugin.
Before moving forward, please note that each article in this series builds on the one before it, so if you're just joining us, please be sure to check out the previous articles in the series:
- An Introduction
- Classes
- Types
- Control Structures: Conditional Statements
- Control Structures: Loops
- Functions and Attributes
Once you're all caught up, let's continue our discussion on the last piece of the paradigm necessary for us to understand before we get into practical application of object-oriented programming within WordPress.
Defining Scope
According the Wikipedia, the first definition of scope is as follows:
In computer programming, the scope of a name binding – an association of a name to an entity, such as a variable – is the part of a computer program where the binding is valid: where the name can be used to refer to the entity. In other parts of the program the name may refer to a different entity (it may have a different binding), or to nothing at all (it may be unbound).
Unless you're an experienced programmer, this is a bit confusing, isn't it? In fact, it may even read like a bit of jargon.
But that's okay because the purpose of this article is to provide a working definition of scope as well as some practical examples as to what it looks like within the context of a program.
So, before we look at the three different aspects of scope in object-oriented programming, let's formulate a cleaner definition.
In short, scope refers to how variables and functions can be access from third-party objects or child objects within the program.
For example, say that you have a BlogPost
object and an Author
object. Next, let's say that the Author has attributes for first_name
and last_name
and the BlogPost
wants to access them in order to, say, display them on the screen.
Perhaps a high-level illustration would help:
In this post, the BlogPost
is requesting name information from the Author
class. Notice that in the diagram above, the class name is in the first blog, the attributes in the second block, and then the empty third blocks are usually reserved for functions.
But that's beyond the, ahem, scope of this article.
Remember: Classes typically represent nouns, attributes represent adjectives, and functions represent verbs or action that the object can take. To that end, classes normally encapsulate their information in strategic ways such that how they work is kept hidden and what they can do is demonstrated by their publicly available functions.
In order to do this, variables and functions must be given a certain scope that grants other objects access to their information. These type of objects include third-party objects that want to leverage the data represented by a class, and another type of object represents an object that inherits information from that class.
Inheritance is beyond what we're going to cover in this particular article; however, we will be covering this a bit later in the series for those who are brand new to object-oriented programming.
So, with that said, we're ready to take a look at a practical example of scope including how we've been using it thus far in the series and how it impacts design decisions moving forward.
All About Public, Private, and Protected
The primer above should have explained, at least a high-level, what scope is and how it matters, but if not, then perhaps the following sections will.
Specifically, we're going to be taking a look at each of the types of scope that variables and functions can have, we're going to explain what each one means, and then we're going to explain when you would want to use each of them.
Before we move forward, note that the public
, protected
, and private
keywords can be used to scope both attributes and functions. This matters because the rules that apply to attributes are also applicable to functions.
With that said, let's take a look at each of the keywords.
Public
Simply put, public
attributes and functions are available to every type of object that's attempting to access the variable or the function.
For example:
<?php class Author { public $first_name; public $last_name; public function set_first_name( $name ) { $this->first_name = $name; } public function set_last_name( $name ) { $this->last_name = $name; } public function get_first_name() { return $this->first_name; } public function get_last_name() { return $this->last_name; } // Other class details... }
Given this setup, any object that calls on an instance of this object can not only access the $first_name
and $last_name
attributes, but can also change them. Similarly, any object that calls an instance of object, can access the functions to retrieve the name and change the name.
So it raises the question: What's the point of having these functions if the attribute is made public? I mean, it's redundant, isn't it? Yes. And we'll be answering it later in the article once we talk about the private
keyword.
Protected
Next, protected
attributes and functions are available within the context of the class in which they are defined, but not for third-party objects. That said, they can be called from within their own class, but not from external classes.
<?php class Author { protected $first_name; protected $last_name; protected function set_first_name( $name ) { $this->first_name = $name; } protected function set_last_name( $name ) { $this->last_name = $name; } protected function get_first_name() { return $this->first_name; } protected function get_last_name() { return $this->last_name; } // Other class details... }
But there is an exception: subclasses.
For example, let's say that you define a class named Contributor
which is a subclass of Author
, this means that the Contributor
has access to all of the protected
(and public
) attributes and functions of its parent class.
<?php class Contributor extends Author { /** * This class has access to all of the attributes * and functions of its parent class, Author. */ }
Given the code above, this means that you can call methods such as get_first_name()
from within the Author
class or within the Contributor
class but not from any external classes.
Admittedly, subclasses have more to do with inheritance which is something that we'll be talking about more later in the series; however, I bring this up to provide an important clarification between public
attributes and functions and private
attributes and functions.
Private
in short, private
attributes and functions lock the attributes and functions into the class in which they're defined. This means that no external object or subclasses can access any of the information.
Clearly, this is the strictest form of scope but that's not to be read as if it's a bad thing (or a good thing). Instead, it's meant to provide a way for certain information to stay hidden (or abstracted) within the context of the class in which it is defined.
Going back to our first example, let's take a look at how we can refactor the class such that it provides the maximum amount of utility for both external classes and subclasses.
<?php class Author { private $first_name; private $last_name; private function set_first_name( $name ) { $this->first_name = $name; } private function set_last_name( $name ) { $this->last_name = $name; } private function get_first_name() { return $this->first_name; } private function get_last_name() { return $this->last_name; } // Other class details... }
First, this example demonstrates poor use of the private
keyword.
In this example, not only are the attributes inaccessible, but the functions aren't accessible either. In other words, to other objects in "the outside world," this class appears to have nothing available. Even worse, not even subclasses can access any of this information.
In short, the code doesn't really make sense.
So, let's refactor this a little but more such that the attribute remains hidden (and thus inaccessible to third-party objects), and we'll specify a way for third-party objects to retrieve the names but will only allow the actual class and its subclasses to change them:
<?php class Author { protected $first_name; protected $last_name; public function get_first_name() { return $this->first_name; } public function get_last_name() { return $this->last_name; } // Other class details... }
Of course, this is just an example. Obviously, we're leaving out some of the implementation details such that we don't know what details may call for, say, the names to be updated.
But it doesn't matter: This shows a complete example of how private
, protected
, and public
scoped aspects of a class can work in conjunction with one another to provide a safe, strategic way to access information.
Abstraction and Information Hiding
As far as scope is concerned, you can make the argument that it all comes down to abstraction and information hiding.
That is to say that classes (which are blueprints for object, if you recall from our earlier articles) should strategically organize their information such that:
- information that should only be accessible and relevant to it should remain
private
- information that should be accessible by itself and its subclasses should be protected
- information that should be accessible by third-party objects should be public
In fact, I'll go a step further and say that you're not likely to actually see many attributes marked as public
. Instead, you're more likely to see the attributes marked as protected
- for the purposes of subclassing - or private
, so that their data can be managed by functions that are scoped appropriately.
Initially, this sounds relatively simple, right? And the concept itself isn't terribly complicated, but when it comes to building systems that rely a number of different objects all working together to provide solid abstraction, clean interfaces by which third-party classes and subclasses can interact with it, and efficient ways of organizing information, it can become more challenging - there are a lot of moving parts to consider.
With that said, this is one of those things that writing code, interacting with other developers, and reading code can breed experience.
For whatever it's worth, I'm not afraid to admit that these are still strategies with which I struggle not because I don't understand the concepts, but because trying to provide the cleanest class implementation as possible can be difficult, especially in a system that's apt to change.
But that's content for another post.
Of course, if you have questions or comments about anything regarding the topic of scope, don't hesitate to leave them in the comments.
What's Next?
Starting in the next article, we're going to begin incorporating some of this information into a practical application of building a WordPress plugin.
So for those of you who have been waiting to see how this series works in conjunction with WordPress, the next article should begin to bring all of the concepts together as we continue the series with our own WordPress plugin using the concept of object-oriented programming.
Comments