Leveling Up: Understanding Objects

This article was originally published in PHP|Architect magazine in the January 2017 issue. These articles are all copyright by David Stockton. You may be able to purchase the issue here.
Table of Contents

As developers, we understand how our programs work. Perhaps that’s an assumption. Some of us understand some of how certain aspects of our code works. Others, but fewer, understand all aspects of how the code we write works. As developers who are improving and making the transition from junior to mid-level and to senior and beyond, our understanding increases as we learn ins and outs of the language, the application and the techniques that work to build successful applications. Over the next few months, we’ll be building up a solid foundation of object-oriented concepts and patterns, how they work, and how object-oriented code can be used to build more maintainable software.

Some of you are likely quite familiar with OOP. This article may not be for you, but I hope there are some aspects that I’ll cover that will be new or open up new ways of thinking. This month, though, I want to address developers who want to learn more about OOP.

Some Background

I realized a few days ago, that sometime this year, I’ll have been writing code for 30 years. I’ve been doing it professionally (read: getting paid for it) for nearly 20. I started with BASIC on an Apple II clone. In college, I learned enough Fortran to test out of the class and then went to C and C++ and Java. We covered the concept of “class” in C++, sort of, but despite being an object-oriented language, there was really no discussion or learning about objects in the Java class. We all just learned that our classes filled with functions all worked if the function definitions started with public static and they stopped working if we removed static or changed public to something else, even though the code could compile.

In 1997, I was tasked with building a website that allowed users to find information about articles concerning women in tech and computing. I’d built some basic sites with HTML and some garbage JavaScript that would animate elements around the page, thanks to Adobe GoLive, but I hadn’t yet built anything that would dynamically create different pages based on user input. I did some research, considered Bash for the job, quickly found that it was going to be a nightmare and went back trying to find answers for something that would work. During my quest to find a solution, I stumbled on ASP but it required an expensive development tool and web server.

I even considered writing C and using CGI, but fortunately, I stumbled on PHP and some tutorials on webmonkey.com. They were undoubtedly awful and full of security issues, but I had no idea at the time. Every site and tutorial I found (thanks, Alta Vista, Yahoo! and WebCrawler, and a little bit Google) relied on register globals, database examples included queries that were built with string concatenation, usually directly from PHP’s superglobals. PHP 3 didn’t support objects. The scripts were easy to follow, mostly. You started at the top, read down, and everything was mixed together. HTML, code, SQL queries. In some cases, there was a file full of just functions that would be require_onced into another file, but that was typically the extent of the organization and structure.

Shortly after I started learning PHP on the Homesite web server, PHP 4 was released. PHP 4 had some primitive object support, but really nothing like what we’ve had since around PHP 5.2. I remember trying to learn OOP from my procedural background was a struggle. The early examples I found were ill-conceived and there wasn’t a lot of explanation. I came to the conclusion that OOP was not something that helped with anything.

With PHP 5, the language improved and gained better support for OOP over the years. While PHP still supports coding procedurally, much of the current code you’ll see written in the language is object oriented, or taking advantage of the OOP features PHP brings. And here we are now. I’ve been developing my PHP code using OOP concepts for more than a decade now. I want to share some of the things I’ve learned in hopes that I can help you come to a solid understanding much more quickly than I was by avoiding some of the pitfalls that took me a long time to get around.

Understanding Objects

When you’re starting out with OOP, many of the examples start with ideas and concepts and objects that have real-world counterparts. Whether it’s trying to explain the concept of inheritance using animals or vehicles, or building shapes that can all calculate their area or perimeter using the same method names, I feel that thinking of the objects of code having the same sorts of constraints as real-world objects can often lead to an incorrect mental model of what they are and what they can do. As such, if I use one of these examples to help illustrate a concept, it helps to separate and remove the limitation of objects needing to behave like, or even have a real-world equivalent at all.

Let’s take a quick look at what I mean. Suppose there’s a Car class that does all sorts of Car things. Cars need engines, so we give the car an engine.

$engine = new Engine();
$myCar = new Car($engine);
$yourCar = new Car($engine);

In the example above, we have two separate and distinct objects that are cars, and they have an engine. They can do all the sorts of things that cars with engines can do. However, both cars have the exact same engine. In the real-world, this is ridiculous. Every car in the real-world needs its very own engine. But in OOP, it’s perfectly legitimate and often desirable to provide the same object to other objects at the same time during the same execution of a program. However, there are design decisions that need to be considered when doing this sort of thing.

Consider the two cars with one engine example. Suppose the car provides us some methods like turnOn and pressGas. We build our class so that if the car is on, pressing the gas will move it forward, and if the car is off, pressing the gas has no effect. So taking our two cars we run the following code:

$myCar()->turnOn();
$yourCar()->turnOn();
$yourCar()->pressGas();
$yourCar()->turnOff();
$myCar()->pressGas();
$myCar()->turnOff();

If the intent of the code was that both cars were going to drive forward, the reality is the way we’ve built the code would probably result in something else happening. Since the engine is shared between the cars, the engine will be turned on by both cars, at which point the engine is running. Then the $yourCar gas pedal is depressed and the car lurches forward. Then it shuts off the engine.

The code then continues with $myCar and presses the gas. However, since the engine is shared, it’s now off and $myCar goes nowhere. There are numerous ways to design the system differently so that this is not an issue, but my point is that we still have to build and design systems in such a way that they do what we want and don’t do what we don’t want.

You may be wondering why there’s only one engine for both cars. In the Zend Engine, objects are assigned by reference so $engine always refers to the same instance of an object, even if we pass it in to more than one object that needs an engine.

Classes And Objects

Object-oriented programming starts with classes. You may have heard the terms used interchangeably, but they are different. Classes are a description of the shape of the data, behaviors, and dependencies of an object. An object is an instance or instantiation of a class. To put it another way, and using another analogy, a class is related to an object in much the same way a blueprint relates to a house. With that out of the way, let’s continue.

Understanding Scope

Scope in terms of programming refers to what parts of a program can see or use it. PHP supports a number of different scopes for variables. First up, we have superglobals. These are variables that are typically defined and assigned by PHP, in most cases before your script starts. They including variables like $_SERVER, $_REQUEST, $_SESSION, $_GET, $_POST and others. They are accessible by everything in your program without the global keyword. It’s usually in your best interest to avoid using these in your code directly. It’s better to abstract usage of these into as few places in code as you can. I prefer to let whatever framework I’m using deal with those variables usually.

Next, we have globals. These are also variables that are available everywhere in your program. Unlike super globals, unless the code we’re talking about is not defined in a function or class, you have to tell PHP that you want to access the global. Again, this should be avoided at all costs. Globals can be dangerous in that they lead to unpredictable execution and bugs that are difficult to track down. Because they can be changed by anything within your code, changing the order that certain bits of code run can cause it to have a completely different result.

Once we introduce classes, there can be variables at the class level. These are class static variables. They belong to the class, not an object or instance.

class Samoflange
{
    public static $doohickey;
}

If a static class variable is defined as public, it is effectively a global variable, but rather than accessing it via $doohickey it is accessed via Samoflange::$doohickey. Whether these variables are defined as public, protected, or private, they are all effectively global. The protected and private static class variables are just globals that cannot be read from everywhere.

Next, we have instance variables or variables that belong to a single instance of a class. These are the fields or attributes that can be used to hold on to state and dependencies of an object.

Finally, we have the local variable scope. These variables are defined, and used, and eventually destroyed when the method or function completes. By the way, if you’ve heard the term “method” before and not understood what that is, it’s just a function that is defined within a class. The value of local variables can live beyond a function or method if they are returned.

Visibility Modifiers

When starting out, it seems that knowing as much as possible about how every aspect of the code works is important. For a programmer, knowing it all is good. However, from the perspective of the code, it’s best to limit what any given piece of code knows about as much as possible. To use another real world analogy for this point, imagine how difficult it would be to drive a car if we had to know every aspect of how a car works. If we were required to understand that pressing on the gas moves a lever (the pedal) which pulls a cable which is attached to another lever which opens a… and the… so more gas is pumped through the… and then, you know… um, stuff happens and the car goes faster. If we were required to know or keep in mind all the workings of the car’s systems in order to drive, we’d probably have a lot fewer drivers and very few people would know how to drive more than a single vehicle. Instead, all of the complex workings of the car are hidden behind a few common interfaces that are shared between different vehicles. We have gas pedals and brake pedals and a steering wheel. Whether your car has a rack and pinion, power steering, articulated steering or something else, the steering wheel abstracts that all away so all we need to know is when we turn the wheel clockwise, the vehicle goes to the right and counter-clockwise goes to the right. It means in general if you know how to drive one car, you can drive almost any other car.

This hiding of information and functionality is called encapsulation in OOP terms. It means we should only expose the minimal amount of information we can for the system to work. PHP provides visibility modifiers we can use to allow the language to enforce what parts of the program can see variables or access a method. Some other languages (like Python) don’t have this and rely on convention, and variable naming to infer that certain variables or functions should not be used by developers. You may see old PHP code where variables and functions are prefixed with an underscore (_), which was how PHP 4 code hinted at visiblity and trusted convention to enforce it.

PHP provides three levels of visibility in objects: public, protected, and private.

Public variables and methods are available to anything in our code with access to the instance of that object, as well as any code in the object itself.

Protected hides variables and methods to the outside world, and makes sure the code is only available within the class and its inheritance hierarchy. Don’t worry if you don’t know what I mean by inheritance, we’ll get to it later.

Finally, private variables and methods are available only to instances of that class. This is not a typo. In addition to private variables and methods being usable within a single instance, if another class of the same type has access to a different instance, it can access private variables and call private methods on that other instance.

Inheritance of Classes

I want to talk about inheritance, mostly to say that I feel that in most cases, inheritance is not the right way to solve a problem. However, since it seems every introduction to OOP includes a discussion on inheritance, I should not pretend it doesn’t exist. Inheritance allows a class to be built that is based on another class. If you can describe the relationship between two classes with “is a” then inheritance might be a good solution. However, if the relationship is not “is a” then it is definitely the wrong solution.

In PHP we use inheritance with the extends keyword. For example:

class Foo extends Bar
{
}

In this case, we’re saying a Foo “is a” Bar. Foo should be providing some different but related functionality, potentially overriding or augmenting existing functionality. Over the next few articles, I hope to show and convince you (if you don’t already believe it) that we should prefer composition over inheritance. This means that we can build powerful solutions by combining objects and delegating work from one object to another, rather than making a bunch of objects that inherit and change functionality.

If inheritance is not your thing, or you feel that a class should never be extended, you can declare it final. This ensures at the language level that nothing else can extend it. Marco Pivetta wrote a good post arguing that classes which implement an interface and no other public methods should be always marked final. You can read it at http://ocramius.github.io/blog/when-to-declare-classes-final/.

Do One Thing And Do It Well

I’ve said for years that if you have to use the word “and” to describe what the purpose of your class is, then it’s doing too much. The same can be said at the method level and arguably at the namespace or package level as well. In OOP, we get better, more powerful code by building simple objects and combining them. If you’re building a class and you find that the functionality you’re creating could be delegated or moved out, chances are it’s a good idea to do that. It may end up that your original design was fine with the functionality happening in a single object, but later as requirements change and the software evolves, more classes and objects may make themselves apparent.

Creating classes that are limited in what they do as well as what is exposed via the public visibility modifier means that maintenance of the code will be easier, testing it will be simpler, and refactoring, updating, adding and changing functionality will be more straightforward and cheaper.

Conclusion

Over the coming months, we’ll focus more on different patterns that I see and use in code, talking about why those patterns exist, what they are good for and how they should be used. This month, I talked some aspects of my philosophy towards object oriented programming and design which should help in understanding why I build some things in the way I do. I hope you’ll join me next month. If you’ve got a particular pattern or question about object oriented design or programming that you’d like to read about, please be sure to reach out and let me know.