I have trouble writing OOP in PHP... I understand the concept but I never create classes for my projects... mainly because it's often a small project and nothing complex. But when I read OOP, it seems more difficult to code than writing simple procedural statements. It also seems to take a lot of room as well with so many empty abstract classes and that can be easily lost in the land of objects... it's becoming like a junkyard to me.
Also, I noticed that virtually all instructions on how to use OOP use "car" or "cat" or "dog" analogies. Hello... we're not dealing with animals or cars... we're dealing with windows or consoles. You can talk about analogies to death and I will never learn. What I want is see a code that's written to show how objects are created - not, "aCow->moo!"
For example, I want to see a browser window object displaying say... three inputs. I want to see an "object" created to output a window with three inputs then I want to see how overriding works, like change the window object to display only two inputs instead of three inputs. I think that would make learning more easy, wouldn't it? Any recommended tutorials of that nature instead of quacks, moos, and woofs.
Here are a few examples of classes that I find to be in the genre of OOP. Enjoy!
Start with a Base Form Class that can output <input>
fields. Very simple, has an array to hold the fields that are going to be outputted, have a method for adding fields, and has a function that will display the form to the page.
class Form
{
protected $inputs = array();
public function makeInput($type, $name)
{
echo '<input type="'.$type.'" name="'.$name.'">';
}
public function addInput($type, $name)
{
$this->inputs[] = array("type" => $type,
"name" => $name);
}
public function run()
{
foreach($this->inputs as $array)
{
$this->makeInput($array['type'], $array['name']);
}
}
}
$form = new form();
$form->addInput("text", "username");
$form->addInput("text", "password");
$form->run();
Then, lets say we wanted to create a class that can deal with the special style of <textarea>
inputs. Well, we override the run function to filter out any input that have the type
textarea
, and redirect them to another function that we create that can deal with <textarea>
s
class textAreaForm extends Form{
public function run()
{
foreach($this->inputs as $array)
{
if($array['type'] == "textarea")
{
$this->makeTextArea($array['name']);
}
else
{
$this->makeInput($array['type'], $array['name'];
}
}
}
public function makeTextArea($name)
{
echo '<textarea name="'.$name.'"></textarea>';
}
}
$textareaForm = new textAreaForm();
$this->addInput("text", "username");
$this->addInput("text", "password");
$this->addInput("textarea", "comment");
What we have done is taken a base class that holds enough functionality to be usable, and then created another class that derives from it to add additional functionality.
Some may argue that in this specific example, the second class should just be added to the first class, because all forms should be able to process <textarea>
s , but it is a start place.
Another example might be a database. You build a base database class that has all of the functions that would be required to access a Database, but then you can create a class derived from it to specialize in Postgres Databases.
First create a database class that lays out the functions that would be needed to interact with a database. It doesn't do anything yet, but it ensures that whoever is going to write a specialized class knows the functions they need
class Database
{
public function connect($host, $user, $pass, $database)
{
// This function doesn't do anything normally
}
public function query($query)
{
// again, nothing
}
public function select_db($database)
{
// FOR THE LAST TIME! NOTHING!
}
}
You could even make all of the functions abstract so if someone doesn't implement them, they get a PHP error
abstract class Database
{
public abstract function connect($host, $user, $pass, $database)
public abstract function query($query)
public abstract function select_db($database)
}
And then add functionality to it based on the type of database we are using.
class MySQL extends Database
{
public function connect($host, $user, $pass, $database)
{
mysql_connect($host, $user, $pass);
$this->select_db($database);
}
public function query($query)
{
return mysql_query($query);
}
public function select_db($database)
{
mysql_select_db($database);
}
}
and Finally
This one I came upon recently. Lets say that I wanted to create an object that just contained a bunch of data. Well, I can very easily do that by using a new instance of stdClass
. But, lets say that I wanted to make the class from an array. We can specialize stdClass
and make it easier to work with:
class stdDataClass {
/**
* Constructs the Object
*
* @param array|object $fields An array or object of data to be assigned as
* class members on initalization of the class
*/
public function __construct($fields = array())
{
// Check if the passed in variable is an object
if(is_object($fields))
{
// Grab the accessible variables and use them as the fields
$fields = get_object_vars($fields);
}
// Check if any fields were passed in, if they were, assign them to members
if(count($fields) > 0)
{
foreach($fields as $key => $value)
{
$this->$key = $value;
}
}
}
// .. more stuff ...
}
This makes a array you pass in like this
$obj = new stdDataClass(array("test" => "foo"));
Be accessible like this
echo $obj->test; // echos 'foo'
Just a note, I never extends stdClass
as stdClass
has no methods or properties, and is basically an empty class.
Basically, anything that can be accessed from outside of a class is considered an 'interface'. It means that these are the function and variables that another class can interact with freely.
AKA, in this class, there is only 1 function get
in the interface:
class Mine{
public function get($key);
private function doSecretStuff();
}
If you want to make 'sure' that there are certain interfaces in a class, you create an interface
interface Mine{
public function get($key);
}
This assures that any class that implements Mine
will have the functions in its interface
class Yours implements Mine
{
public function get($key);
}
The following class for example will result in the PHP script giving an error and stop running:
class Yours implements Mine
{
public function noGetHere($key);
}
The importance of an interface is simple, as it ensures that you are able to call a function. In this case, this function will NEVER get a 'method undefined' error.
function test(Mine $class)
{
echo $class->get("Hello");
}
Because of the use of Type Hinting (making sure that $class
either is an instance of Mine
, extends Mine
or implements Mine
), $class
can never not have the method $class->get();
. I dare you to make an example in which this exact function, combined with the above interface, results in a method not found error.
The final keyword is a method to make sure that something can't be changed. Just because the OP argued that in OOP, you can make a cat say 'bark', I feel like discussing this. It also furthers the example of why I have no life. :)
Basically, if you create a cat
class Cat
{
public function speak()
{
echo "Meow";
}
}
You can write over the speak function like so
class BarkingCat extends Cat
{
public function speak()
{
echo "Bark";
}
}
But, if you use the keyword final
to make the method immutable, the above class will have an error, saying that you cannot overwrite functions that have declared the final
keyword.
class Cat
{
final public function speak()
{
echo "Meow";
}
}
There we go, no more barking cats. select_db($database); }
public function query($query)
{
return mysql_query($query);
}
public function select_db($database)
{
mysql_select_db($database);
}
}
and Finally
This one I came upon recently. Lets say that I wanted to create an object that just contained a bunch of data. Well, I can very easily do that by using a new instance of stdClass
. But, lets say that I wanted to make the class from an array. We can specialize stdClass
and make it easier to work with:
class stdDataClass {
/**
* Constructs the Object
*
* @param array|object $fields An array or object of data to be assigned as
* class members on initalization of the class
*/
public function __construct($fields = array())
{
// Check if the passed in variable is an object
if(is_object($fields))
{
// Grab the accessible variables and use them as the fields
$fields = get_object_vars($fields);
}
// Check if any fields were passed in, if they were, assign them to members
if(count($fields)
The reason animals, cars etc are used is that the easiest way of understanding OOP is to use real-world objects:
So you'll be needing an object of 'window', with a method to create an input. Although cats would be a better analogy...
final
keyword. - Chacha102
Forget the quacks, moos, and woofs.
To really get object-oriented programming, you have to get past those "a dog is-a mammal" metaphors. They don't translate into most types of applications. Object-Oriented programming is so much more effective when you think in terms of roles, responsibilities, and behaviors.
I would really recommend this book to help you out:
Object Design: Roles, Responsibilities, and Collaboration [1]
It was the first book I read where I finally "got it."
[1] http://rads.stackoverflow.com/amzn/click/0201379430There are some good examples here. The top voted answer (which was accepted) does a great job of explaining the basics, and is certainly better than many of the FlyingCar extends Car implements Flying and Car extends Vehicle and Vehicle extends ManufacturedGood examples you might get in school or textbooks.
When I first learned OOP after coming from C, it didn't really click for me either. I used classes as like C structs: just a way to lump variables together. I also had accessor methods, because you're supposed to, all books shoed them. At first, they just seemed like extra typing instead of using public properties.
As time went on I started adding other methods to my classes, and objects become "whole" instead of special structs. Bundling the code together makes maintenance and trying to understand the code easier. It cleans up your code quite a bit to be able to write
myThing.doBehavior(1, 3, false);
someThingSubclass.doBehavior(2, 7, true);
instead of
do_behavior_for_thing(&myThing, 1, 3, false);
do_behavior_for_thing_subclass(&someOtherThing, 2, 7, true);
After a while and you internalize that, you'll use objects and become comfortable. Then one day you'll use inheritance (which is the real secret power) and see just how much easier your life becomes (if done correctly). Compare putting the top and bottom code above into a loop:
Thing theThings[] = {myThing, someThingSubclass, aThirdKindOfthing};
for (int i = 0; i < theThings.length; i++)
theThings[i].doBehavior(7, 3 * i, true);
vs.
Thing theThings[] = {myThing, someThingSubclass, aThirdKindOfthing};
for (int i = 0; i < theThings.length; i++)
if (theThings[i].kind == 1)
do_behavior_for_thing(&theThings[i], 7, 3 * i, true);
else if (theThings[i].kind == 2)
de_behavior_for_thing_subclass(&theThing[i], 7, 3 * i, true);
....
The top loop is two lines. I can keep adding subclasses of Thing to my array and it works fine. In the bottom loop, every time I need to handle a new kind of object, I need to edit the if statements.
Game example
It makes it easy to make small changes to existing objects. Let's take a game, something like Robotron or Geometry Wars where enemies might chase the player. Think of an enemy who blindly chases the user's current position, we'll call him Zombie.
What if you want to add a second, harder enemy, called SmartZombie? You could just copy the Zombie class and edit it, but that would leave you with a bunch of duplicate code. But why not change the Zombie class from something like this:
public class Zombie {
public NextMove makeNextMove(GameState game) {
TargetPos pos = game.getCurrentUserPosition();
// process from there
}
}
to
public class Zombie {
protected TargetPos getTargetPos(GameState game) {
return game.getCurrentUserPosition();
}
public NextMove makeNextMove(GameState game) {
TargetPos pos = getTargetPos(game);
// process from there
}
}
With that little change, you can make your new Zombie chase the user's predicted position by overriding one little method:
public class SmartZombie extends Zombie {
protected TargetPos getTargetPos(GameState game) {
// Calculate where the user will be by the time we could catch him
}
}
Now, when the game asks the Zombie class for his next move, he will walk to where the user is. But if the game is given a SmartZombie instead, without having to know that something different needs to happen, the SmartZombie's makeNextMove function will be called (inherited from the Zombie class). makeNextMove will call the SmartZombie's getTargetPos (since we overrode the Zombie's method) and instead go towards the user's predicted position.
You can use this to easily make other zombies. You could make one that goes towards a random place, one that follows other zombies, all sorts of things. Each of these is a simple change with the above model, letting you have only one copy of the makeNextMove function (which could be really long and involved because it uses A* pathfinding, terrain detection, random staggering, trap avoidance, and other fancy things).
You don't even need to setup the getTargetPos when you first write the class. If you don't know you'll need to access it later, you don't need to make a method for it. When the time comes that you do need to make it easy to change some piece of functionality, that's when you can edit the Zombie class to put the part you need to be able to change into a small function you can easily override.
In my daily work
The system I spend my time on has to interface with many external systems. The basic operations are the same, but the way we communicate can be wildly different (XML, HTTP, other). Even individual implementations can be very different (between two XML interfaces).
But we have a class somewhat like this:
public abstract class abstactSystemInterfacer {
public ReturnValue contactOtherSystem(InputData data);
public boolean interpretResponse(ReturnValue value);
public Status checkWithOtherSystem(Thingy thing);
protected void helpfulMethodForSubclasses(....);
}
The code in the heart of the program is given a subclass and just calls contactOtherSystem and other methods it needs. It doesn't need to know if we're using XML to talk to the other system. It doesn't know at all.
So we can add new code without having to change the main loop. It doesn't need to have a new block of an if or switch statement added when someone new appears. If we have to work with someone new tomorrow who uses some method we've never used before (such as putting weird files in special FTP directories), we can do it without having planned for it before.
This kind of thing makes your life very easy, and the core code very clean. It's up to the subclasses to handle all the details. If you are making a game, you can make enemies this way. Each one implements their behavior in a function, and the game engine calls it. When you make a new kind of enemy, it's as simple as making a new class and instantiating it.
Over time, as you get tons and tons of classes, things can get a little unwieldy. When that happens, there is often commonalities. So instead of every SystemInterfacer subclass being a direct subclass, you can make a new class called AbstractXMLSystemInterfacer. All the XML SystemInterfacers subclass that. Since it contains code that is common to all the XML systems you deal with, you can save duplication and prevent bugs.
When you have something that matches well to objects and inheritance, it's a great tool. It can make your life SO much easier.
OOP isn't always necessary
As I said, not everything needs OOP. Small programs can easily be made that wouldn't benefit from inheritance. I often write little tools to make automate some little process. These are usually one file, a few functions. The programs could even be much bigger. But if they only ever process one kind of "thing", OOP doesn't really add much over procedural code. Don't worry if you don't see how to make all your programs OOP... they just might not fit the OOP mould.
Conclusion
It took me a while to 'get' OOP because I tried to teach it to myself. I learned programming from books and tinkering before I could take programming classes, in C and Basic. The idea of objects and OOP was pretty foreign from how I was used to doing things, and I didn't have a lot of experience in the fist place. It wasn't until I started doing some non-trivial programming assignments (more than a few functions and one or two files) that asked me to use OOP that I really had a chance, and the utility of it really clicked.
Once I had a reason to use it, I got it pretty fast. As you use it in more and more assignments, you'll get it too. From my experience, and those of my classmates in school, it's not one of those things you can just read about and start applying immediately. It's a bit of a different, sort of a mindset or way of thinking.
Most things are easier to understand if you know at least a little about the abstraction layers directly above and directly below it. I never got OOP until I read a little about design patterns (a level of abstraction above most OOP tutorials; Head First Design Patterns is a good read) and a little about higher order functions, function pointers, virtual function tables, and data structures (a level below; how OOP works under the hood).
Also, in PHP the type system is so loose that OOP and polymorphism really isn't needed for flexibility the same way it is in, say, Java, C#, or C++. It's only useful for organization, which isn't really important in small projects.
OOP is useful when you have large, complex systems that have many repeated operations that can be accumulated together into a simple reference.
If you're just doing something simple, something where a procedure would take 5 lines and you're probably never going to need it again, then OOP is most likely overkill. Too many people want to solve their problems by OOP, when it might not be the right call; just because you have a hammer does not mean that everything is a nail. Having an object that contains a single string, for instance, is pointless-- just use the string. Having an object that stores thirty strings and some numbers, not so pointless, because now you can treat all of that mess of data as the same thing for reading, writing, etc.
OOP is also useful if you want to get into patterns [1]. I never really understood OOP beyond the accumulation I just described until I figured out patterns. MVC [2] is the best way I've found to write the programs I write, and if you ever have to write a program that must produce auditable logs, the Mediator [3] pattern is the right thing to do.
[1] http://en.wikipedia.org/wiki/Design_patternsTo directly answer your question:
I don't know how you think so I don''t know why it would be hard for you. I had trouble with OOP at first too. Some people have trouble understanding the analogies.
Another way to understand OOP is as follows:
Objects are nouns Methods can be understood as verbs Properties - Adjectives parameters/arguments - adverbs
Class Noun{
Private adjective;
Public function __construct(){
}
function verb(adverb){
//do something
}
}
Commands are Verbs. Functions are groups of commands.
Whatever. I think this works. - Moshe
I agree. I never understood those dog, cat telephone car analogies.
OOP, to me, is really a set of techniques to help fight the war against code-duplication.
I always thought 'Re-usability' was a luxury like a handy library or framework being shared from one project to another. But, no, it is vital to Don't Repeat Yourself within any project if you want to keep your sanity.
So, the 'noun objects' are really only a tiny aspect of OOP. OOP is really about eradicating repeated pieces of knowledge. See http://en.wikipedia.org/wiki/Don%27t_repeat_yourself
Also what really hit it home for me was when someone explained classes as responsibilities as opposed to things.
i.e
//responsible for cats
abstract class CatLover {
protected $numberofcats;
abstract public function takeCatToVetToGetSpayed()
}
class Spinster extends CatLover {
protected $numberofcats =100;
public function takeCatToVetToGetSpayed() {
//TODO
}
}
etc.
Better OOP style for Form Class Example presented by hobodave would be somethink like that:
abstract class FormElement {
protected $type;
protected $name;
protected $value;
public function __construct($value = null) {
$this->value = $value;
}
public function setName($name) {
$this->name = $name;
}
public function getType() {
return $this->type;
}
public function getName() {
return $this->name;
}
}
class InputText extends FormElement {
public $type = 'text';
public function __toString() {
return sprintf('<input value="%s" type="%s" name="%s">', $this->value, $this- >type, $this->name);
}
}
class Password extends InputText {
public $type = 'password';
}
class Textarea extends FormElement {
public $type = 'textarea';
public function __toString() {
return sprintf('<textarea name="%s"></textarea>', $this->type, $this->name);
}
}
class Form {
protected $inputs = array();
protected $action;
public function __construct($action) {
$this->action = $action;
}
public function addElement(FormElement $FormElement) {
$this->inputs[] = $FormElement;
}
public function __toString() {
$form = '<form action="'.$this->action.'">';
foreach($this->inputs as $FormElement)
$form .= (string) $FormElement;
$form .= '</form>';
return $form;
}
}
$Form = new form;
$Login = new InputText;
$Password = new Password;
$Form->addElement($Login);
$Form->addElement($Password);
echo $Form;
Like you see, now we have full power of OOP programming. We don't repeat ourselves just take a look on class Password that inherits from InputText that inherits from abstract class FormElement it has only one line in body but power of FormElement class + InputText class
Think of OOP as a way of extending the way we think about life into a program. Stuff doesn't just happen each day on its own, people, places, and things do actions, and create things, and that's why stuff happens. Say you want to write software to help people with real estate transactions. A person can buy a house for an amount of money and the ownership transfers to the person who bought it right. Let's analyze that:
Object: person
attribute: age (extraneous)
Object: house
attribute: value
Object: sale
attribute: house (instance of house)
attribute: amount (a general property expressed as a number)
attribute: buyer (instance of person)
attribute: seller (instance of person)
Now you could begin to code up a skeleton of objects in PHP with this analysis, something like this:
<?php
class Person {
public $age = 50;
public function buyHouseAndReturnSaleInstance($houseInstance)
{
$sale = new Sale();
$sale->house = $houseInstance;
$sale->amount = $someAmount;
$sale->buyer = $this; // $this is a reference to the current instance of the class in which it is, so in this case it would reference the person object who is doing the buying.
$sale->seller = $houseInstance->owner;
$houseInstance->owner = $this;
return $sale;
}
}
class House {
// This variable would be set dynamically in reality
public $value = 50000;
}
class Sale {
public $house = $instanceOfHouse;
public $amount = 50000;
public $buyer = $instanceOfPerson;
public $seller = $anotherInstanceOfPerson;
}
?>
so in programming it helps to be able to analyze things in this way and write programs against that analysis.
Take some PHP framework (I recommend CodeIgniter because of its weight and ease of use), then you'll be forced to learn OOP. It was hard for me to understand concepts of OOP at first, but now I'm starting to see benefits. It can be really hard to switch if you're used to procedural programming (it was hard for me too because I'm always sceptical about trying something new).
Here is an example:
class Person
{
private name;
// This is the constructor. Here you can set default values when you create theobject.
// In this demo I pass along a name when I create a new student.
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
$student = new Person('Oliver');
echo $student->getName();
I use a class like this to create and display a gallery for my website.
Take a looka at some MVC framework such as CakePHP - it uses OOP extensively.
Using MVC frameworg is generally a good idea.
Writing a class just to dump simple HTML is really not going to teach you much. I suggest you look into some MVC framework like CodeIgniter [1] in which you create classes for controllers and models. Once you create your first real controller class you will see how OOP can be used for something useful, like replacing all the if statements with class methods for example.
[1] http://www.codeigniter.comBecause you're doing it in PHP where it was shoehorned in later.
Try playing around with SmallTalk to get a better feel for it, then you can apply the ideas in PHP.
You are right, real programming problems are not simple like Cat and Dog examples..
And the actual problem with Cat,Dog or similar examples in books/lectures shows only one concept at time. For example for explaining Inheritence: Cat extends/implements Animal , thats it. AND AFTER EXPLAINING EACH CONCEPT BOOK ENDS
Real problem comes when your Cat and Dog gets 4 legs and 2 ears and relationship like cat is afraid of Dog, dog loves dog, dog can eat cat. these is not covered in many books.. only few books explains it properly.
But OOP helps when you really understand it properly, and use it properly..which is hard... By the way.. You should read Head First: OOAD [1] book (its in Java, but concept explanation is very good) and book has 2 very practicle real world application not Cat/Dog 2 class application....
[1] http://headfirstlabs.com/books/hfooad/I was in exactly the same position as you. While knowing the theory I couldn't apply objects to my PHP code.
I would suggest starting with the simplest two kinds of classes such as classes that contain only member fields, and classes that contain only methods. Use only such classes and with time you will actually feel the need to have both fields and methods in a class, to extend classes and so on.
For example in usual procedural PHP site you have some data (probably as arrays) and some functions with this data. Simply convert your data to classes with only fields and use them as glorified arrays, and wrap your similar functions into classes and use them as utility classes. It sounds simple and trivial, but try it and you will be surprised how much you will learn and understand.
Many people fail to realize the benefits of OOP structure in PHP. In other languages, like Java and C#/VB.NET, it is much more explicit so you can totally see the benefit. Example:
interface IFormField
{
function GetValue();
}
class TextBox
implements IFormField
{
function GetValue()
{
...
}
}
What does GetValue() return? String? Integer? Array? Even if it returns a String, you can subclass it and then change it to return an Integer. PHP allows you to do this.
In other languages such as Java and VB/C#.NET you could do something like:
public interface IFormField
{
IFormFieldValue GetValue();
}
public class TextBox : IFormField
{
public IFormFieldValue GetValue()
{
...
}
}
So now we know exactly what GetValue() returns. When extending the TextBox class, the method signature must be the same so we can guarantee child classes will be consistent.
If you are working on small projects, you probably do not see the benefit of creates classes and such. When developing applications on larger teams, or if you outsource work, having code like this will save a lot of time.
As for classes taking up too much room, check this out:
What can you build in 600 lines of code?
[1]
OOP is hard for you because PHP does not force you to write 100% OOP and it is very tempting to start cheating... and then learning OOP takes way longer
You need practice with 100% OOP languages. C++ is not a good choice because you can still cheat and ignore it. Java is not 100% pure but when I used it, I immediately noticed that the only way to write a good Java program is using OOP. Smalltalk is more pure!
Just try to do some small projects with Java and learn UML along some patterns. UML is not necessary to learn OOP but it helps a lot to stick the idea to your head and start thinking in that way.