Classes and OOP (Part 2)

  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8388
  • Loc: USA

Post 3+ Months Ago

Classes and OOP (Part 2)



1.0 Previous Tutorial


This is the second instalment of a series of tutorials on the topic of classes and OOP (object-oriented programming).

First Tutorial

In the previous tutorial we learned how to set-up a basic class, fill it with functions and class variables, how to use those functions and variables inside and outside of the class and different kinds of visibility and how they affect the class, functions and class variables.

1.1 Introduction to Tutorial


It is now time to go a little bit farther and dwell into the wild realms of classes and OOP.

As a reminder, in the previous tutorial, we left off with the following class. We are going to build on that in this tutorial.
PHP Code: [ Select ]
class fruit
{
 
    private $amount = 2;
 
    public function eat()
    {
        // Chew
    }
   
    public function amount($number)
    {
        if($number < 11)
        {
            $this->amount = $number;
        }
    }
   
}
  1. class fruit
  2. {
  3.  
  4.     private $amount = 2;
  5.  
  6.     public function eat()
  7.     {
  8.         // Chew
  9.     }
  10.    
  11.     public function amount($number)
  12.     {
  13.         if($number < 11)
  14.         {
  15.             $this->amount = $number;
  16.         }
  17.     }
  18.    
  19. }

We would take about the different contexts in which we could write the classes and about magic functions; what they are and what they do.

2.0 Object Versus Static


There are two different ways we can call on the classes and use their functions and variables. They are:
  • Object
  • Static
These are easy and don't (shouldn't) take too long to learn. What you are familiar with at the moment is object. An example of a class used in an object context is:
PHP Code: [ Select ]
$product = new fruit();
 
$product->amount(3);
 
$product->eat();
  1. $product = new fruit();
  2.  
  3. $product->amount(3);
  4.  
  5. $product->eat();

Mostly, classes are used in an object context, but there are times when programmers want to use classes in a static context. That would be (doing the same thing above in a static context).
PHP Code: [ Select ]
fruit::amount(3);
 
fruit::eat();
  1. fruit::amount(3);
  2.  
  3. fruit::eat();

Though that won't work at the moment since the class was written in an object context, that would be the usage of a class that would be written in a static context.

2.1 Differences Between Object and Static


In order to use our class as a static class it needs to be converted to be in a static context rather then in an object.
PHP Code: [ Select ]
class fruit
{
 
    private static $amount = 2;
 
    public static function eat()
    {
        echo "Eating " . self::$amount . " apples.";
    }
   
    public static function amount($number)
    {
        if($number < 11)
        {
            self::$amount = $number;
        }
    }
   
}
  1. class fruit
  2. {
  3.  
  4.     private static $amount = 2;
  5.  
  6.     public static function eat()
  7.     {
  8.         echo "Eating " . self::$amount . " apples.";
  9.     }
  10.    
  11.     public static function amount($number)
  12.     {
  13.         if($number < 11)
  14.         {
  15.             self::$amount = $number;
  16.         }
  17.     }
  18.    
  19. }

Now if we run:
PHP Code: [ Select ]
fruit::amount(3);
 
fruit::eat();
  1. fruit::amount(3);
  2.  
  3. fruit::eat();

It would work. If we run that code to the following class, it would also work (the class is written a little bit differently).
PHP Code: [ Select ]
class fruit
{
 
    private static $amount = 2;
 
    public function eat()
    {
        echo "Eating " . self::$amount . " apples.";
    }
   
    public function amount($number)
    {
        if($number < 11)
        {
            self::$amount = $number;
        }
    }
   
}
  1. class fruit
  2. {
  3.  
  4.     private static $amount = 2;
  5.  
  6.     public function eat()
  7.     {
  8.         echo "Eating " . self::$amount . " apples.";
  9.     }
  10.    
  11.     public function amount($number)
  12.     {
  13.         if($number < 11)
  14.         {
  15.             self::$amount = $number;
  16.         }
  17.     }
  18.    
  19. }


I want to stop here for a bit and point out a few things that you most likely have already noticed yourself in the code above.

The first thing I want to add here is the usage of the keyword static before every function and class variable that we have set there. This tells the class that those particular variables are to be used as a static, making the class be in a static context. What I have found out that functions don't need the word static in order for it to use static variables or be used as static, but it's my opinion that it's better to define them as static if you have intentions of using it as a static function.

Now, as to why use a class in a static context? There are a few answers to that, and most of them leading to "an easy way out". Most of them has "laziness" involved :)

It is bad practice to use/do classes in a static context though (in most cases), so I wouldn't recommend it. I put this here so you know they exist, what they are (and some bits and pieces about it are mentioned later on in the tutorial). It is bad practice because classes in a static context have a good number of bad characteristics about them.

Some of them are: (In no particular order)
  • Added hidden dependencies
  • Forfeits the power and strengths of OOP (object-oriented programming... SOP? static-oriented programming?)
  • Unknown global state
  • No polymorphism
For further reading on static classes

3.0 Magic Methods


Most people enjoy magic, optical illusions or just any kind of illusions for that matter. PHP provides magic methods (or functions) for you to use. Magic methods are special functions which are triggered a certain way and act a bit differently then normal functions. You could set the magic methods and define them your own way.

There are 14 different kind of magic methods our there to help you in the creation of your system. You don'nt have to use all of them in a class, a certain number or any. You could write an entire class without using even 1 if you don't need one. The magic methods are:
  1. __construct();
  2. __destruct();
  3. __call();
  4. __callStatic();
  5. __get();
  6. __set();
  7. __isset();
  8. __unset();
  9. __sleep();
  10. __wakeup();
  11. __toString();
  12. __invoke();
  13. __set_state();
  14. __clone();
As you would notice, all of the magic methods start off with a double under-line (__).

3.1 construct()


php.net - For Further Reading
Quote:
Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.

What happens with this magic method (function) is that whenever a class is initiated then this function is immediately ran. For instance:
PHP Code: [ Select ]
class fruit
{
 
    function __construct()
    {
        echo "Class 'fruit' has being initiated.";
    }
 
}
  1. class fruit
  2. {
  3.  
  4.     function __construct()
  5.     {
  6.         echo "Class 'fruit' has being initiated.";
  7.     }
  8.  
  9. }

What happens here is that whenever you initiate that class:
PHP Code: [ Select ]
$product = new fruit();

The system would immediately print "Class 'fruit' has being initiated." (without the double-quotes) because that __construct function has being set and defined to do that.

Constructors may be called the same name of the class and it would do the same exact thing. For instance:
PHP Code: [ Select ]
class fruit
{
 
    function fruit()
    {
        echo "Class 'fruit' has being initiated.";
    }
 
}
  1. class fruit
  2. {
  3.  
  4.     function fruit()
  5.     {
  6.         echo "Class 'fruit' has being initiated.";
  7.     }
  8.  
  9. }

That is the same thing as the fruit class right above this one.

Note:
You can call on the constructor again after initiating the class.
PHP Code: [ Select ]
$product = new fruit();
 
$product->amount(3);
 
$product->__constructor();
 
// Or if we had 'fruit' instead of '__constructor'
$product->fruit();
  1. $product = new fruit();
  2.  
  3. $product->amount(3);
  4.  
  5. $product->__constructor();
  6.  
  7. // Or if we had 'fruit' instead of '__constructor'
  8. $product->fruit();


3.2 destruct()


php.net - For Further Reading
Quote:
The destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence.

This magic method is called upon closure of the class. This method is usually used to close any connections that may have being opened during the use of the class, maybe record something into a log-file or whatever else you might need to do with the information after the class has being used.

Note:
The classes won't be closed in the same order as they were initiated (if you ran more then one class). You can also run this method manually the same way you would run any class method outside of the class.

3.3 call() and callStatic


php.net - For Further Reading
Quote:
__call() is triggered when invoking inaccessible methods in an object context and __callStatic() is triggered when invoking inaccessible methods in a static context.

Inaccessible methods are methods that haven't being set/defined in the class. For instance, in our fruit class, we don't have the function "set_amount()" set, but if we have the magic method __call() or __callStatic set, then we would have a default action for methods that doesn't exist and yet the script tried to find.

For instance, if we try to run the following code:
PHP Code: [ Select ]
$product = new fruit();
$product->swallow();
  1. $product = new fruit();
  2. $product->swallow();

The PHP engine would give as an error by default (a fatal error) if we don't have __call defined. But if we have __call defined, it would do the defined action as default. (Like log the error instead of displaying it to the users for everyone to see).

3.4 get()


php.net - For Further Reading
Quote:
__get() is utilized for reading data from inaccessible properties.

What this handy little magic function does is sets a default action on what to do when the script is trying to retrieve an inaccessible property. For example:
PHP Code: [ Select ]
$product = new fruit();
 
echo $product->fruits;
  1. $product = new fruit();
  2.  
  3. echo $product->fruits;

In that usage (if you remember the class we wrote and how it was when we left off) it won't find the actually variable "fruits" and if we have the function "__get()" set with a default action (like log the event) the class would call on __get() every time a property is not found.

3.5 set()


php.net - For Further Reading
Quote:
__set() is run when writing data to inaccessible properties.

This happens when you try to set a value to a class variable that has not being set in the class. Under normal circumstances, PHP engine would set that variable for you anyway, this allows you to gain more control over that process (like if you want to log the event).

3.6 isset()


php.net - For Further Reading
Quote:
__isset() is triggered by calling isset() or empty() on inaccessible properties.

This method allows you to take control over the normal isset() function. For example:
PHP Code: [ Select ]
class fruit
{
 
    function __isset($name)
    {
        if(isset($name))
        {
            return 'Is Set';
        }
       
        return 'Is Not Set';
    }
 
}
 
$product = new fruit();
 
echo isset($product->everything);
  1. class fruit
  2. {
  3.  
  4.     function __isset($name)
  5.     {
  6.         if(isset($name))
  7.         {
  8.             return 'Is Set';
  9.         }
  10.        
  11.         return 'Is Not Set';
  12.     }
  13.  
  14. }
  15.  
  16. $product = new fruit();
  17.  
  18. echo isset($product->everything);

If you run that, that would print "Is Not Set" on the screen. The class would call this function every time you use isset(); anywhere in the system with class variables.

3.7 unset()


php.net - For Further Reading
Quote:
__unset() is invoked when unset() is used on inaccessible properties.

This magic function behaves the same way as __isset() except it's for the function unset.

3.8 sleep() and wakeup()


php.net - For Further Reading
Quote:
serialize() checks if your class has a function with the magic name __sleep(). If so, that function is executed prior to any serialization. It can clean up the object and is supposed to return an array with the names of all variables of that object that should be serialized. If the method doesn't return anything then NULL is serialized and E_NOTICE is issued.

The intended use of __sleep() is to commit pending data or perform similar cleanup tasks. Also, the function is useful if you have very large objects which do not need to be saved completely.

Conversely, unserialize() checks for the presence of a function with the magic name __wakeup(). If present, this function can reconstruct any resources that the object may have.

The intended use of __wakeup() is to reestablish any database connections that may have been lost during serialization and perform other reinitialization tasks.


3.9 toString()


php.net - For Further Reading
Quote:
The __toString() method allows a class to decide how it will react when it is treated like a string. For example, what echo $obj; will print. This method must return a string, as otherwise a fatal E_RECOVERABLE_ERROR level error is emitted.

The way I understand this is that it creates a string representation of the object in case we ever feel the need to echo the entire object.
PHP Code: [ Select ]
$product = new fruit();
echo $product;
  1. $product = new fruit();
  2. echo $product;

Under normal circumstances, it would give us a catchable error, but if we provide a __toString() function, the script would do that function instead. For example we have the following class:
PHP Code: [ Select ]
class fruit
{
 
    function __toString()
    {
        return '$' . __CLASS__ . '->' . __FUNCTION__ . '();<br />';
    }
   
}
  1. class fruit
  2. {
  3.  
  4.     function __toString()
  5.     {
  6.         return '$' . __CLASS__ . '->' . __FUNCTION__ . '();<br />';
  7.     }
  8.    
  9. }

And we use it like:
PHP Code: [ Select ]
$product = new fruit();
 
echo $product;
  1. $product = new fruit();
  2.  
  3. echo $product;

That would return:
Quote:
$fruit->__toString();


3.10 invoke()


php.net - For Further Reading
Quote:
The __invoke() method is called when a script tries to call an object as a function.

For example we have the following function:
PHP Code: [ Select ]
<?php
class fruit
{
 
    function eat()
    {
        echo 'Eating an apple<br />';
    }
   
    function __invoke($function)
    {
        echo 'Yay! Class as function!!!<br />';
        $this->$function();
    }
   
}
  1. <?php
  2. class fruit
  3. {
  4.  
  5.     function eat()
  6.     {
  7.         echo 'Eating an apple<br />';
  8.     }
  9.    
  10.     function __invoke($function)
  11.     {
  12.         echo 'Yay! Class as function!!!<br />';
  13.         $this->$function();
  14.     }
  15.    
  16. }

And we use it as:
PHP Code: [ Select ]
$product = new fruit();
 
$product('eat');
  1. $product = new fruit();
  2.  
  3. $product('eat');

It would print out the following:
Quote:
Yay! Class as function!!!
Eating an apple

Kind of an interesting way of getting to use a class... I think it would get confusing though later on in the process :lol:

Note:
This particular magic function can take any number of variables as long as you put it in the definition. The following is also ok:
PHP Code: [ Select ]
<?php
class fruit
{
 
    function eat()
    {
        echo 'Eating an apple<br />';
    }
   
    function swallow($fruit)
    {
        echo 'Swallowing ' . $fruit[0];
    }
   
    function __invoke($function, $arguments = null)
    {
        echo 'Yay! Class as function!!!<br />';
        $this->$function($arguments);
    }
   
}
 
$product = new fruit();
 
$product('eat');
 
$product('swallow', array('Apples'));
  1. <?php
  2. class fruit
  3. {
  4.  
  5.     function eat()
  6.     {
  7.         echo 'Eating an apple<br />';
  8.     }
  9.    
  10.     function swallow($fruit)
  11.     {
  12.         echo 'Swallowing ' . $fruit[0];
  13.     }
  14.    
  15.     function __invoke($function, $arguments = null)
  16.     {
  17.         echo 'Yay! Class as function!!!<br />';
  18.         $this->$function($arguments);
  19.     }
  20.    
  21. }
  22.  
  23. $product = new fruit();
  24.  
  25. $product('eat');
  26.  
  27. $product('swallow', array('Apples'));

That prints:
Quote:
Yay! Class as function!!!
Eating an apple
Yay! Class as function!!!
Swallowing Apples

(In normal circumstances, you won't write "Yay! Class as function!!!". I did it in the tutorial to show the function of the function (:lol:) better.

3.11 set_state()


php.net - For Further Reading
Quote:
This static method is called for classes exported by var_export() since PHP 5.1.0.


3.12 clone()


php.net - For Further Reading
Quote:
Once the cloning is complete, if a __clone() method is defined, then the newly created object's __clone() method will be called, to allow any necessary properties that need to be changed.

Yes, you can clone a class in PHP (a topic for a later tutorial).

4.0 Conclusion


In this tutorial we learned about writing and utilizing classes in an object context and a static context, and we learned the differences between them. We also learned that in most cases it is bad practice to write classes in a static context.

We also learned about the 14 magic methods that PHP has to offer in writing classes and the uses of them.
  • Anonymous
  • Bot
  • No Avatar
  • Posts: ?
  • Loc: Ozzuland
  • Status: Online

Post 3+ Months Ago

Post Information

  • Total Posts in this topic: 1 post
  • Moderator: Tutorial Writers
  • Users browsing this forum: No registered users and 2 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.