0

Suppose I have a two classes called User and Product. Both of these need to be saved in a database.

A third class called PersistencyHandler handles all the database interactions (in order to obey both Single Responsability Principle and Dependency Inversion). Here is what this class looks like:

<?php
/**
 * Class PersistencyHandler
 * Handles database using PDO API
 */
class PersistencyHandler{

    /**
     * PDO connection used to save objects into.
     * @var $conn PDO
     */
    private $conn;

    /**
     * PDODatabaseSaver constructor.
     * @param $conn PDO
     */
    public function __construct($conn){
        $this->pdo = $conn;
    }

    /**
     * Saves the given object in the database
     * @param $object mixed
     */
    public function save($object){

        // as PHP does not support classic method overloading for different
        // types of objects, this is the cleanest solution I've been able to find.
        // And it's still pretty dirty...

        if($object instanceof Product) {
            $this->saveProduct($object);
        } else if($object instanceof User) {
            $this->saveUser($object);
        } else {
            throw new UnsupportedOperationException("Cannot save object, unsupported type."); // custom class
        }
    }


    private function saveProduct(Product $object){
        // save Product into database
    }

    private function saveUser(User $object){
        // save User into database
    }

}
?>

I come from Java experience and I am sure that using instanceof is a very poor practice (at least in Java). For instance, in Java, I used to solve problems like this using overloaded methods.

I have checked php.net and other websites (including this one) but I haven't found a good answer to my question:

What is the better way to achieve the same behaviour of the above code in a correct way?

Notice that I have a single method with a single argument and the called method is decided by the type of the argument.

Z. Alessandro
  • 69
  • 3
  • 9
  • Take a look at this question : https://stackoverflow.com/questions/4697705/php-function-overloading – Anurag Srivastava Mar 08 '20 at 15:41
  • Strategy pattern. – u_mulder Mar 08 '20 at 15:42
  • @AnuragSrivastava this is not really my use case. That question is asking about overloading with different number of arguments. I always have a single argument passed to my method. – Z. Alessandro Mar 08 '20 at 15:47
  • @u_mulder This pattern seems pretty interesting for this situation, thank you! – Z. Alessandro Mar 08 '20 at 15:48
  • @Z.Alessandro You probably missed the first line in the accepted answer. `You cannot overload PHP functions.` – Anurag Srivastava Mar 08 '20 at 15:49
  • @anuragSrivastava I did not miss the first line. Your answer does not help me solving this problem. I am asking for a way to achieve the same result with cleaner code. My title might be a bit misleading – Z. Alessandro Mar 08 '20 at 15:53
  • You must edit your title to ask exactly what you are looking for :) You ask `how to do X?` and I linked to an answer which says `X isn't possible` – Anurag Srivastava Mar 08 '20 at 15:54
  • Did you read through the explanation of the problem? Fixed the title anyway, thanks – Z. Alessandro Mar 08 '20 at 15:56
  • Hi, I'm not so knowledgeable about patterns, principles or technical language. But I'd suggest looking at how Wordpress solves this. It uses a database interaction class, and any new other objects that need to be saved implement their saving method usually through functions. For your case I really don't see the point of handling it all in one class. But as I said I'm not very technically educated. –  Mar 08 '20 at 15:57
  • @SarPutnik Thanks for your reply. The problem with interacting with database in different classes is the following: imagine you were using MySqli API to save things into database. What happens if you realize you'd better use PostegreSQL instead of MySQL? You would have to change **every** class. Having all in one class makes it much much easier for maintenance. I'll make sure to have a look at how Wordpress solves this! – Z. Alessandro Mar 08 '20 at 16:01
  • use an interface, implement it and then extend the base class `PersistencyHandler` should really only have save and it calls the save() implemented on the child.. your making an orm basically. see how redbeanphp or such do it. – Lawrence Cherone Mar 08 '20 at 16:05
  • @LawrenceCherone Could you please provide a short example, please? I'm not sure I understand it. – Z. Alessandro Mar 08 '20 at 16:09

1 Answers1

1

A solution is to use a dynamic call (similar to reflection in Java):

public function save($object)
{
    $mtd = 'save'.get_class($object);
    if(method_exists($this, $mtd))
        call_user_func(array($this, $mtd), $object);
    else
        throw new UnsupportedOperationException("Cannot save object, unsupported type.");
}

Note: if you use namespaces, you will need to adapt the code (get_class() returns the qualified name).

Olivier
  • 13,283
  • 1
  • 8
  • 24