Jump to content

[SOLVED] Need "practical" example of how OOP can be useful vs procedural php. =)


5kyy8lu3

Recommended Posts

Hi.  First off, I'm not here to start a OOP vs proc. flame war.  I'm here because I'm trying to learn OOP and so far all the tutorials I've read have extremely simple examples in which the OOP takes 3-4 times the code to accomplish something vs procedural code.

 

Like one tutorial I read used a class with a method to save a name to the variable and a method to get the value out of the variable.  That took WAY more code to do than to just save the value straight to the variable and echo that string variable.  I know there's more to OOP code than that, but the examples have been so simple I'm not grasping the purpose of it yet.  Simple is good, but it's so simple I'm not getting the point of the OOP.

 

Could someone write me or link me some "practical" example of SIMPLE object oriented php code where it makes more sense than to code it with procedural php?  I absolutely love the concept of modular code, so I really want to learn it but I'm having a hard time understanding what OOP is all about.  Basically, I need an example of how using OOP is better than just using functions.

 

To help, I'll explain what I DO know.  I know it helps keep code clean since you typically keep your class in a separate file you include/require.  I know that functions are called methods and variables are called properties.  I also know you can "reuse" a method with inheritance, which I could see being handy.  I somewhat understand the keywords and syntax, but as far as theory, that's all I understand so far.  ANY input at all would be much appreciated.

 

(I've read several tutorials, and I own a few php books but none of them mention OOP, I'm guessing they were written before php5, and my friends who DO understand OOP can't explain it on a level I can understand) Thanks =)

Link to comment
Share on other sites

I personally think classes should be used as a storage for very flexible and reusable functions. Like when you have have a piece of code that you run many times over, but with slight variations, such as Logging in to a social networking site. A class would hold alot of functions that you can use in lots of different ways, but in the end, you know that you'll use it lots of times.

 

I wrote my own class for User management, that include Editing, Registration, Logging in, Restricting Pages, Deleting and Getting Info. Why did I write a class? Because I know I'll use that class in lots of different projects, but it's very easy to customize. Like, I set the table name at calling (though it has a default (everything I use has a default)) and with Login, I have an array that allows me to customize what sessions are set. The get Info will let me get the info of all members, or just one, or just a list of members. The registration lets me set what fields should be inserted. The restriction lets me set what session value to look at for what values to allow.

 

Basically, I think a class should be used when you have something you do often, and you want to create one collection of functions to use in lots of different projects, and those functions should be flexible.

Link to comment
Share on other sites

Hmm.  I have lots of function I use but I don't see how using a class would be any different from having a php file with all my functions in it that I include.  That's basically what I'm trying to figure out.  You put your functions you use alot into a class, I put mine straight into a php file that I include. (which I do)  That's what I'm not understanding.

Link to comment
Share on other sites

I don't really get it either. I suppose maybe it's the organization? I mean, you don't have to worry about writing two function with the same name. And classes have global variables within themselves. I only just started on classes, but that's my best guess

Link to comment
Share on other sites

dude I feel you.  It took me a very long time to really get past the "why bother, it just seems like a more bloated way of doing things" mentality.  And 9/10 times the logic holds true, not because that's how OOP is, but because 9/10 times people aren't really coding something that really needs to be coded in that fashion in the first place. Or else, they aren't coding with true OOP mentality in the first place.

 

Thing is, you are not really going to find any code examples of OOP being better than procedural (at least, not "simple" ones), because OOP is all about a state of mind and way of coding, and also, OOP mentality is on a larger scale than procedural.

 

In order to understand OOP better, look at a normal procedural function.  Why do you use functions?  You have a bit of code that is highly reusable and instead of having to write it all out every time, you can just write it out once, wrap a label around it, and call the label (the function name).

 

You can hand out your function to other people and they don't have to know what's going on in the function; all they need to know is what it does.  This is pretty much the exact same idea behind OOP. 

 

So you ask, "But why not just hand them a bunch of functions, same thing!" Ah but here's the thing.  Go back to your function.  The thing most people tend to overlook about functions is scope.  When you are inside a function, you are within a different scope.  Variables created in a function have their own namespace.  So for example:

 

$x = 123;

function blah() {
  echo $x;
}

 

$x will not echo anything in the function because as far as the function scope is concerned, $x doesn't exist.  But if you were to do this:

 

$x = 123;

function blah() {
  global $x;
  echo $x;
}

 

The function will now echo 123, because you have specified that you want to use the $x from the global level. But this is generally considered to be bad practice.  Why is that?  It is bad practice because you are defeating the purpose of scope.  You are creating a way to disregard the boundaries.  You are making it possible for something outside of the function affect what happens inside the function. 

 

So why is that so bad?  The reason why it is bad, is because the point of a function is that it's supposed to be a piece of reusable code that since you know for 100% sure what it's supposed to be doing every single time, you can abstract it away into that single label, and know exactly what's going to happen when you call it.  But if you transcend scope, you can no longer 100% guarantee that. 

 

Something goes wrong, a bug you're trying to track down.  Well it could be happening in the function but it could be because something is happening with $x somewhere else in your script.  When you are debugging, your function shouldn't be one of the places you should have to look for the bug, because you should know 100% already what its supposed to be doing.

 

It's like trying to debug your code by looking under the hood of the built-in functions in php, like for instance, if you have a script that goes through an array to do something but it's not working, do you look in to seeing if your (for example) in_array is really searching all the elements in your array, or do you just assume that it faithfully checks all your array elements, instead of only a couple?  You assume it is doing exactly what it is supposed to.  It accepts certain arguments, gets called a certain way, and that's it.  I cannot set some variable on the outside to change what it does on the inside.  This allows me to know 100% that it is going to do what it says it will do, regardless of what situation I put it in.

 

This is the same thing that that should apply to a function you make yourself, and this is the same core idea behind OOP.  The core idea of OOP is adding additional layers of scope, in order to abstract pieces of code, only on a larger scale.  OOP is in concept the exact same as a function, only on a larger scale. Script vs. snippet, sort of thing. 

 

And bigger scale means more things to consider. When you code procedural style, you have an arsenal of functions that you use, but then a bunch of other code that actually uses it.  Variables, loops, blahblah whatever.  You make a login script or form validation script or whatever.  But then you make enough login scripts for people and you quickly come to the conclusion that not only are the functions themselves reusable, but the whole damn script is reusable, minus minor tweaks.  So you can wrap another label around it: a class; a collection of all the variables and functions you use.  Create some arguments that can be passed to it to handle those minor variations.

 

Which brings us back to scope.  Just like with the function, you want to make sure that random things outside of that class does not affect what goes on inside the class.  If it does, then you can no longer guarantee the class will do what it is supposed to be doing 100% of the time. So you can set "permissions" on things.  Set it to where people can directly call or set a method (function) or property (variable) from outside of the function, or only from other things within the same class, etc...

 

You have "getter" and "setter" methods in a class to retrieve or set a property value, instead of directly accessing the property, because that creates a scope, a boundary for those properties.  If the only way the property value can be changed is through the setter method, this gives you guarantees everywhere else that that property is always going to be xyz (a certain variable type, certain string length, whatever the case may be), so that other methods or whatever will not have to all do the same thing. 

 

Like for instance, if you have two methods that use the same property, well if the property is supposed to be a string of 10 characters in a certain format, would you write out validation in both those methods, or would you create another method (function) to validate it, since its the same code being used over and over?  That is in essence what that setter function is.  The setter function's job is to take the raw value and make sure that the property only gets set as that 10 character string.  Truncate it, cast it, pad it, call something else that spits back an error, whatever.  Point is, in those two methods using that property, you don't have to deal with it, because you've abstracted it away with those getter/setter methods.

 

Thing is, you are in fact sort of indirectly programming in an OOP style already, but just don't realize it.  When you for instance try to call in_array, but pass it too many or two little arguments, or pass it the wrong type of data, you get an error spit back at you, right?  Do you think that happens within the in_array function?  No! 

 

in_array (and all other built-in functions) are in fact not really functions, but methods (in principle).  We just don't have to do something like $this->in_array because it's already implied, because we can't work on a level lower than in the script that we send to the parser.  Kind of the same principle as with javascript and being able to do document.whatever instead of window.document.blah.

 

Point is, when we use in_array, it is actually one of those "getter" methods in the php core that first validates the arguments being passed to it.  If things aren't good, it calls other methods that ultimately spit out an error or whatever.  If its good, then it calls the real methods that do the job as described in the manual.

 

Most people just don't think of it, and that's the point! All of that stuff has been abstracted away, so that all we have to think about and consider is the description and rules of engagement as specified in the manual.  And that's the same thing with OOP.

 

OOP as a way of programming is somewhat more complex than even this, but in my experience of seeing people struggle when they first start out (and in my own experience as well), the main stumbling block is scope.  Once you really understand (or at least, make the connection, because I'm sure you understand scope just fine, on a single function level), the rest falls into place a lot easier.

 

Link to comment
Share on other sites

Well, stuffing a bunch of reusable functions into a class != OOP.  You're treating it the same way as a normal library file that you'd wind up including/requiring.  Having it in a class doesn't make it magically better.

 

Like CV said, OOP is a design methodology - a way of coding.  It focuses on making code modular, reusable, and extensible.  I always enjoy the LEGO analogy.  Objects are like LEGO bricks.  There are some that serve special purposes (like those cool slanted pieces in the Space sets), but most are pretty generic.  They all have their own properties - size (a 2x2 brick is different than a 3x2 brick), color, thickness (plates vs. bricks) - and when used together can create any kind of shape.  More importantly, a brick used in one shape can most likely be used in another.  The same goes for objects in OOP - the objects used in one system can most likely be used in another.

 

OOP describes how to make those bricks, and how to combine them to do something useful.  Nothing more.

Link to comment
Share on other sites

and to add scope into the lego analogy: You have a 2x2 brick well the point of scope is that you know that that 2x2 brick will always be 2x2 and won't magically or unexpectedly change into a 2x3 brick.  Unless you intentionally make it that way, but then that in and of itself becomes a brick that would not change.  Point is, scope enforcement (wrapping things in functions and classes, using getter/setter methods, etc..) allows for those lego blocks to be taken from your robot and used in your pirate ship, because you know it will fit just the same. 

Link to comment
Share on other sites

Thanks Crayon Violent,

That was some pretty interesting reading (thanks to Nightslyr for bringing lego into it :) ).

Understanding the *reason* behind OPP is (was?) one of the things that I could never get my head round.

I know *how* to do it but have never fully understood why.

 

After reading through your post, and understanding most of it, I feel that much closer to finally understanding the purpose of classes.

 

Thanks for taking time to answer 5kyy8lu3's question.

Do you have a blog? would definatley be worth reading :)

 

Chris

 

Link to comment
Share on other sites

I also struggled to wrap my head around OOP.  Your statement about how it takes a lot more code then doing the same thing procedural was my biggest hang up with OOP, until I finally got the concept.  It was like a light bulb going off!  It fought against using OOP for web applications for a long time because I didn't see the benefit, but now I would never go back.

 

I actually wrote an article on my blog explaining my process for using OOP, targeted towards those wanting to make the leap.  I am hesitant to post it here though because I am new and I don't want anyone thinking I am spamming. 

 

I would love to offer some advice or provide examples though if you have any specific questions that might be a bit fuzzy.  The information posted here is pretty good, but I also understand that sometimes it takes many perspectives before you can fully grasp the concept and usefulness. 

 

One thing to remember about OOP is that it was designed to mimic real world things, people, places, etc.  This forces you to COMPLETELY change they way you design an application.  The other thing to remember is OOP is mainly used for code re-usability.  Once you wrap your head around it you will see why OOP does a FAR better job at this then suing method libraries or other procedural techniques to 'attempt' to accomplish the same thing.

 

LIVE, LEARN, SHARE -- ws

Link to comment
Share on other sites

Do you have a blog? would definatley be worth reading :)

 

Haha no, I do not have an official blog, but I do occasionally get asked that.. dunno though.. 9/10 times if my post is longer than like a paragraph or two, people summarily dismiss it as TLDR.   

 

I actually wrote an article on my blog explaining my process for using OOP, targeted towards those wanting to make the leap.  I am hesitant to post it here though because I am new and I don't want anyone thinking I am spamming. 

 

Kind of a gray area.  Depends on the context, who is making the decision, how the stars are aligned, etc... in general the safest bet would be to post the actual article you wrote.  Some people don't wanna do that though, because of our ToS (nothin' special..just the avg. "if you post something you grant us full rights to use it blahblah" sort of thing) .  Could alternatively put a link to your blog in your signature and then make a post mentioning to go to the link in your sig.  Which is kind of indirectly the same thing, sort of.  But whatever.

 

Link to comment
Share on other sites

Like one tutorial I read used a class with a method to save a name to the variable and a method to get the value out of the variable.  That took WAY more code to do than to just save the value straight to the variable and echo that string variable.

 

This concept is called Encapsulation.  Though it seems like a lot of extra work for something simple, the benefit is in keeping your runtime errors to a minimum if not eliminating them completely.  Like said in other replys, its all about SCOPE!  Here is a write up I did on encapsulation on my blog.  Hope it is helpful.

 

To understand the post we need to start with a class that is already built for a 'Zoo Application'. This class has a public variable called $_animals that is an array of animals in our Zoo.  $_animals is this first example IS NOT encapsulated.  Meaning we can access it's $_animals variable from an instance of the Zoo class Directly.

 

 
$zoo = new Zoo();

// Get animals out of the zoo so we can use them. 
$animals = $zoo->_animals;

 

Starter Code

 

class Zoo
{
    var $_animals = Array();

    function Show()
    {
echo "<h2>Animals in the zoo:</h2>";

foreach ($this->_animals as $animal)
{
	    echo "<a href='?action=speak&animal=" . get_class($animal)
                . "'>" . get_class($animal) . "</a><br />" ;
        }
    }

    function __construct()
    {
	$this->_animals["Cat"] = new Cat("White");
$this->_animals["Dog"] = new Dog("Brown");
$this->_animals["Koala"] = new Koala("Grey");
    }
}

 

Encapsulation:

 

Encapsulation is the process of abstracting your objects characteristics or fields from anything using that object.  The purpose of doing this is so that you can strictly control how your data is accessed, manipulated, and even populated.  By default all of our fields and methods in our class are what we call 'public', meaning they can all be accessed from instances of our class.  $_animals is a public field and can be accessed from our Zoo instances.

 

This works great because we can easily grab our animals from our zoo and get information about them.  The problem with this is, we can now also overwrite the value of the animals in our zoo since we can access it.

 

$zoo->_animals = "Hello World";

 

 

Now suddenly our animals are not animals at all, it is a simple string.  This will lead to all kinds of problems in our program if this happens.  For one, $_animals is expected to be an array so as soon as we try to access a value in it as an array we will get an error.  In addition, our program expects to be able to pull objects from the array and access their methods for speak().  To prevent this from happening we use encapsulation to first hide our $_animals field from everyone else, then we will provide a new way to access it using our rules.

 

The keywords you will use with Encapsulation our 'pubic', 'private', and 'protected'.  Like mentioned above, all fields and class members are public be default.  It is still a good idea to label your public fields with the public keyword however, so that your code is easier to read and for others to understand.

 

Private means, this field can only be used inside the class and by methods of the class.  Meaning, if I set $_animals to private I can no longer access it from our objects instance of $zoo, but I can still use it inside our classes code.  This will keep people from being able to set $_animals to a string value.

 

 

class Zoo
{
    private $_animals = Array();
    ...
}

 

 

Now if we try to access $_animals from our $zoo instance it would result in an error.  This is good, it now prevents people from changing our $_animals value to something other then an array of Animals.  Next we need to provide a way for the class to share it's $_animals with the world.  To do this we are going to create a function inside our class that returns the value of our animals.

 

 

public function Animals()
{
    return $this->_animals;
}

 

 

Now we have provided a way for us to get our animals out of the zoo.  If we call our public Animals() function from our $zoo instance, it will return our array of animals safely saved in our class, however there is  no way for people to change the value of our $_animals field to anything that is not an array of Animals.

 

 

$zoo = new Zoo();
$animals = $zoo->Animals();

 

 

Now things are looking a little more stable.  There is still one problem though. We have no way of adding animals to our zoo.  We hid our $_animals field from the outside world so that it could not be changed to something other then an array of Animals.  We were able to get the value saved in that field by creating a public function that returns it.  This means we can also use a function to create  a method to add new animals to our zoo.

 

public function AddAnimal($animal)
{
    if(get_class($animal) != "Cat"
        && get_class($animal) != "Dog"
        && get_class($animal) != "Koala")
        {
            throw new Exception("$animal is not an allowed Animal type");
}

    $this->animals[] = $animal;
}

 

Now we can add more animals to our zoo if we want to, and we know that the animals they add will either be a Cat, Dog, or Koala, all of which are animal objects.  Now there is no chance that the value of our $_animals field can ever be set to anything that is not an array of animals.

 

This whole process is an example of Encapsulation.  We have encapsulated our $_animals field in this example.  It is generally a good idea to encapsulate all your fields, even if you want to allow complete access to them.  This is not only good coding practice but it also makes your code more consistent and easier to follow.

Link to comment
Share on other sites

hmmm, I have followed through your post wshell  and had a go at the code that you included.... and got nothing :(

I sort of hoped that it would echo something out (yes, I did try echoing $animals )

I may have misunderstood it but I feel that it hasn't made anything any clearer for me :(

I will read your blog entry now, thanks for sending me the url.

 

Chris

Link to comment
Share on other sites

hmmm, I have followed through your post wshell  and had a go at the code that you included.... and got nothing :(

I sort of hoped that it would echo something out (yes, I did try echoing $animals )

 

Sorry Chris,  I just realized that this code would not work without the code for creating the different animals that go in our zoo, which are also classes.  The example I gave was mostly to address the comment about 'getters' and 'setters' which is Encapsulation. 

 

Please note everyone that Encapsulation is just one part of OOP, and this example was only meant to address that little piece of it.  I would post my entire article on this but I think it would be to large for this format.  As the moderator suggested I Am linking to my blog in my signature.  If this is a problem I will gladly remove the link.  My main intention is not to advertise my blog on this forum, it's to help others who struggled like I once did.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.