Page 1 of 1

OOPHP- The Basics of Classes and Objects Rate Topic: ***** 6 Votes

#1 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10667
  • View blog
  • Posts: 39,615
  • Joined: 27-December 08

Posted 29 June 2010 - 02:23 PM

*
POPULAR

As PHP is not a strictly OOP language, it is very easy to slip into sloppier and more procedural code as well as program in PHP one's entire career and not deal with OOP at all. In this tutorial, I will cover the following:
  • Why use OOP over procedural programming, as I have been doing?
  • Encapsulation and modularity
  • Basic class design


Why OOP?- A Look at Encapsulation and Modularity
Object-Oriented Programming is a very different paradigm than procedural programming, revolving around abstract modeling of Objects and their interactions rather than simply throwing code line-by-line at a solution. It allows for a cleaner, more modular, and better encapsulated solution. Let's start by examining some procedural PHP:
$people = array(
    "John Doe" => array("John", "Doe", "Male", 45),
    "Macosxnerd101" => array("Mac","osxnerd101","Male",17)
);

foreach($people as $person){
     foreach($person as $attribute){
        echo $attribute." ";
     }
     echo "\n<br>\n\n";
}



As we can see, we have a multi-dimmensional array modeling a list of people. Great, we can go through with nested foreach loops in O(n^2) time (O(kn) time if you want to do more than the basic analysis) and print out the list, one person per line. But let's examine some of the limitations and down-sides to this approach. First, we don't have any encapsulation here. This means that any element in the 2D array can access any other element, and it is harder to keep the elements in correpsonding arrays grouped together. This is very poor practice, as you the programmer should provide no avenues for accidents resulting in data corruption to occur.

In terms of modularity, we are lacking here as well. First, we really should be using a function to format the String a little better. We really don't know (yes by looking, but not programatically) which attributes are which. Yes, we could key them making an associative array, but this still leaves us with poor encapsulation. In addition, what if we wanted to create more person arrays to be stored in people? We can still design a function fill a new array with the appropriate attributes and push it onto $people, but we are getting down into the area of getting it working vs. getting it working right.


Now, let's examine how OOP can give us a better design, starting with our class. I've commented the individual elements of the class, with a look at the overall design after we finish designing our class.
//here we have a class Person
//which abstractly models a Person
class Person{
 
   //these are instance variables
   //which are associated with each
   //instance of the class
   private $firstName;
   private $lastName;
   private $gender;
   private $age;

   //here, we define the constructor, which 
   //initializes our instance variables
   //the developer can either pass in their own values 
   //or use the pre-initialized values
   //while I did not do any validation here, you certaintly have
   //more power to validate the types and values being passed
   //rather than relying on the user to input something valid
   public function __construct($firstName = "John", $lastName = "Doe", $gender = "Male", $age = 40){
       $this->firstName = $firstName;
       $this->lastName = $lastName;
       $this->gender = $gender;
       $this->age = age;
   }

   //these are our accessor and mutator methods
   //as our instance variables are private, we must use
   //accessor and mutator methods to grant appropriate access
   //or we can choose not to give the desired read or write
   //access. this is the power of encapsulation
   public function setFirstName($firstName){$this->firstName = $firstName;}
   public function getFirstName(){return $this->firstName;}

   public function setLastName($lastName){$this->lastName = $lastName;}
   public function getLastName(){return $this->lastName;}

   public function setGender($gender){$this->gender = $gender;}
   public function getGender(){return $this->gender;}

   public function setAge($age){$this->age = $age;}
   public function getAge(){return $this->age;}

   //this is another magic function that 
   //determines how Person objects react
   //when converted to Strings
   //It is a good practice to output something
   //either very parser friendly for reading 
   //in the data from a File or visually
   //friendly for users, so that it saves
   //you some work down the road
   public function __toString(){
       return $this->lastName.", ".$this->firstName.
              "\nGender: ".$this->gender."\nAge: ".$this->age;
   }
}



Now that we have our class, let's examine some components of the design. Probably the most important concept here is encapsulation. Obviously, our instance variables are private. This means that we only need to know the results when we access or mutate them through the appropriate functions, but not how the code mutates them. In addition, you have more closely related attributes, so it is nearly impossible to accidentally mismatch attributes from two Persons, unlike the 2D and parallel arrays models.

So now that we have designed our class, let's refactor our original example using classes and Objects instead.
$people = array();

//create a John Doe and insert it into the array
$people[] = new Person(); 

//create a new Person Jane Smith, a female
//however, I don't want to adjust the age
$people[] = new Person("Jane", "Smith", "Female");

foreach($people as $x){
   //__toString() is invoked here
   //so there is no need to manually format
   //the Object
   echo $x."<br>\n"; 
}



As you can see, we still have two Persons, but it is much easier to insert new Persons into the $people array because of the constructor and encapsulation. This also allows for a more modular and reusable Person class, rather than reinventing the wheel for each script. In addition, the __toString() function allows for easy, predefined formatting. So now we are down to O(n) vs. O(n^2) (or even O(kn)).

This post has been edited by macosxnerd101: 04 July 2010 - 10:49 AM


Is This A Good Question/Topic? 12
  • +

Replies To: OOPHP- The Basics of Classes and Objects

#2 Dogstopper  Icon User is offline

  • The Ninjaducky
  • member icon



Reputation: 2874
  • View blog
  • Posts: 11,047
  • Joined: 15-July 08

Posted 29 June 2010 - 05:27 PM

Nice lesson mac. Keep them coming!
Was This Post Helpful? 0
  • +
  • -

#3 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10667
  • View blog
  • Posts: 39,615
  • Joined: 27-December 08

Posted 29 June 2010 - 08:02 PM

Thanks! Will do. :D
Was This Post Helpful? 0
  • +
  • -

#4 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3554
  • View blog
  • Posts: 10,335
  • Joined: 08-June 10

Posted 29 June 2010 - 09:16 PM

*
POPULAR

defining properties for lazy coders:
class Person
{
   private 
      $firstName,
      $lastName,
      $gender,
      $age;

# etc.


This post has been edited by Dormilich: 29 June 2010 - 09:17 PM

Was This Post Helpful? 7
  • +
  • -

#5 evinrows  Icon User is offline

  • D.I.C Head

Reputation: 10
  • View blog
  • Posts: 141
  • Joined: 03-August 09

Posted 30 June 2010 - 06:40 AM

This is great! I was just wondering how object oriented programming works in PHP. I have done a lot of OO programming in Java (the only way to program in java, of course) but for some reason was afraid of OO PHP (probably because I had a hard time with it years ago). So simple though, thanks for the tutorial! Now I can feel less afraid learning Code Igniter!

I would love to see more of these tutorials on in depth OO PHP. :)

This post has been edited by evinrows: 30 June 2010 - 06:42 AM

Was This Post Helpful? 0
  • +
  • -

#6 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10667
  • View blog
  • Posts: 39,615
  • Joined: 27-December 08

Posted 30 June 2010 - 09:25 PM

I'm glad you found this so helpful! I'll definitely try to keep the OOPHP tutorials coming! :)
Was This Post Helpful? 0
  • +
  • -

#7 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6078
  • View blog
  • Posts: 23,548
  • Joined: 23-August 08

Posted 05 July 2010 - 07:20 AM

Note: Big-O notation discussion moved to the PHP Programmers forum for better visibility.
Was This Post Helpful? 2
  • +
  • -

#8 creativecoding  Icon User is offline

  • Hash != Encryption
  • member icon


Reputation: 927
  • View blog
  • Posts: 3,209
  • Joined: 19-January 10

Posted 17 June 2011 - 03:10 PM

Why not make those private variables public and cut out those ten lines of accessor and mutator methods? Does making them private improve any sort of security or performance? Why is encapsulation needed? Or is it not needed and just something you had to cover?
Was This Post Helpful? 1
  • +
  • -

#9 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10667
  • View blog
  • Posts: 39,615
  • Joined: 27-December 08

Posted 17 June 2011 - 03:12 PM

Getter and setter methods are used for encapsulation. It is necessary, b/c you don't want another component invalidating or messing up the Object or class functionality by setting the instance fields or static fields to invalid or undesired values. The getter/setter methods help with validation and control. Plus, they can be overridden in subclasses. I have a tutorial on encapsulation as well, which you may find helpful. :)
Was This Post Helpful? 0
  • +
  • -

#10 Atli  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 3719
  • View blog
  • Posts: 5,991
  • Joined: 08-June 10

Posted 17 June 2011 - 03:47 PM

If you don't like the Java-like $foo->setBar('Blah'); method of encapsulation, and would prefer to use the $foo->bar = 'Blah'; way of doing this, but don't want to lose the encapsulation, you can use the Property Overloading magic methods: __get and __set.

Instead of adding a getX and setX method for every property, you can just do:
class foo {
    private $bar;
    
    public function __get($key) {
        if (property_exists($this, $key)) {
            return $this->$key;
        }
        else {
            return null;
        }
    }
    
    public function __set($key, $value) {
        if (property_exists($this, $key)) {
            $this->$key = $value;
        }
    }
}


And all the class variables will now be accessible as if they were public. And defining custom behavior for any single attribute is still just as easy as with the getters and setters. Just add if statements (or something more elaborate) and hand it off to prive setters/getters, or just do your thing right there in the __get or __set.

Also, just in case you are planing on using anything like this in a large project, the @property PHPDoc tag is very useful. IDEs like Netbeans pick it up and use it in the code assist thing, and it helps when documenting large projects.
/**
 * @property string $bar Description of the bar variable.
 */
class foo { ... }


Was This Post Helpful? 3
  • +
  • -

#11 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10667
  • View blog
  • Posts: 39,615
  • Joined: 27-December 08

Posted 17 June 2011 - 04:27 PM

I didn't even know that existed. Thanks for sharing, Atli! :)
Was This Post Helpful? 0
  • +
  • -

#12 kiwi_steve  Icon User is offline

  • D.I.C Head

Reputation: 31
  • View blog
  • Posts: 109
  • Joined: 26-September 09

Posted 29 June 2011 - 04:05 PM

This is awesome... Thanks for the great explanation and clear examples... I'm just converting my brain over from Java to PHP so finding this post is very timely for me.

Cheers for taking the time...

Steve

This post has been edited by kiwi_steve: 29 June 2011 - 04:05 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1