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.

class fruit
{

    private $amount = 2;

    public function eat()
    {
        // Chew
    }

    public function amount($number)
    {
        if($number < 11)
        {
            $this->amount = $number;
        }
    }

}

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:
$product = new fruit();

$product->amount(3);

$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).

fruit::amount(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.

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;
        }
    }

}

Now if we run:

fruit::amount(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).

class fruit
{

    private static $amount = 2;

    public function eat()
    {
        echo "Eating " . self::$amount . " apples.";
    }

    public function amount($number)
    {
        if($number < 11)
        {
            self::$amount = $number;
        }
    }

}

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 Object Constructs - For Further Reading

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:

class fruit
{

    function __construct()
    {
        echo "Class 'fruit' has being initiated.";
    }

}

What happens here is that whenever you initiate that class:

$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:

class fruit
{

    function fruit()
    {
        echo "Class 'fruit' has being initiated.";
    }

}

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.

$product = new fruit();

$product->amount(3);

$product->__constructor();

// Or if we had 'fruit' instead of '__constructor'
$product->fruit();

3.2 destruct()

PHP Object Destruct - For Further Reading

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 Object Call - For Further Reading

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:

$product = new fruit();
$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 Object Get - For Further Reading

__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:

$product = new fruit();

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 Object Set - For Further Reading

__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 Object Isset - For Further Reading

__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:

class fruit
{

    function __isset($name)
    {
        if(isset($name))
        {
            return 'Is Set';
        }

        return 'Is Not Set';
    }

}

$product = new fruit();

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 Object Unset - For Further Reading

__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 Object Sleep - For Further Reading

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 Object toString - For Further Reading

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.

$product = new fruit();
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:

class fruit
{

    function __toString()
    {
        return '$' . __CLASS__ . '->' . __FUNCTION__ . '();<br />';
    }

}

And we use it like:

$product = new fruit();

echo $product;

That would return:

$fruit->__toString();

3.10 invoke()

PHP Object Invoke - For Further Reading

The __invoke() method is called when a script tries to call an object as a function.

For example we have the following function:

<?php
class fruit
{

    function eat()
    {
        echo 'Eating an apple<br />';
    }

    function __invoke($function)
    {
        echo 'Yay! Class as function!!!<br />';
        $this->$function();
    }

}

And we use it as:

$product = new fruit();

$product('eat');

It would print out the following:

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 🤣

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
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'));

That prints:

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 (😆) better.

3.11 set_state()

PHP Object Set State - For Further Reading

This static method is called for classes exported by var_export() since PHP 5.1.0.

3.12 clone()

PHP Object Clone - For Further Reading

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.

This page was published on It was last revised on

Contributing Authors

0

0 Comments

  • Votes
  • Oldest
  • Latest