Application of the Singleton standard for small/large design

Asked

Viewed 448 times

1

I’m building classes for an old project where I used only functions in different files. The goal is clear, to create a reusable code standard for small-scale projects with not very distinct functionalities, and on condition that it can be improved/modified in the future without major efforts.

Currently the project acts as a mini-blog, which is something really simple, I also ruled out the possibility of using some kind of framework.

Área Pública:

  • Read content.
  • Comment on.
  • Play video.
  • Browse between categories.

Administrative Area:

  • Edit/Remove Content.
  • Edit/Remove Comments.
  • Add/Remove/Edit administrators.
  • Add/Remove/Edit categories.
  • In/out.

It turns out I’ve always programmed using the procedural style, and in that I manage almost all my experience in web programming, I also program using the oriented style, but not as often as I’ve been developing the procedural way, so let’s just say I have little experience with POO for the simple fact of not knowing much of its applications and its problems in the real world.

Once I mapped out a schematic for this application that I’m developing, I concluded that I would have no problem using the pattern Singleton. It turns out that so far I have not found a specific case where it is stated that this pattern can be used without problems, since in most of the research, more have been reported low than highs.

I have with me this kind of connection:

class Database {
    static $_instancia,$_erro=false;
    private $_pdo,$_resultado,$_query;
    
    private function __construct(){
        try{
            $this->_pdo = new PDO('mysql:host='.Padrao::get('mysql@host').';dbname='.Padrao::get('mysql@dbname').';charset='.Padrao::get('mysql@charset').';', Padrao::get('mysql@usuario'), Padrao::get('mysql@password'));
        } catch(PDOException $e){
            die($e->getMessage());
        }
    }
    // Singleton
    static function getInstance(){
        if(is_null(self::$_instancia)){
            self::$_instancia = new Database();
        }
        return self::$_instancia;
    }    
    // Select (também auxiliar às restantes acções - CRUD)
    public function query($tabela, $where){
        $campo = $where[0];
        $operador = $where[1];
        $valor = $where[2];
        $sql = "SELECT * FROM {$tabela} WHERE {$campo} {$operador} ?";
        if($this->_query = $this->_pdo->prepare($sql)){
            if($this->_query->bindParam(1, $valor)){
                if($this->_query->execute()){
                    $this->_resultado = $this->_query->fetchAll(PDO::FETCH_OBJ);
                    return $this;
                } else {
                    self::$_erro = $this->_query->errorInfo()[2];
                }
            }
        }
        return false;
    }
    // Resultados
    public function resultado(){
        return $this->_resultado;
    }
    // Erro na consulta
    public static function erro(){
        return self::$_erro;
    }
    
    mais métodos...
}

It has a CRUD and the instance itself, the class itself is complex, I edited this one and removed some of the methods, yet I kept in it the essential.

Next I have class Config also responsible for most of the configurations, in the various classes, and some useful methods:

// Classe para configurações
class Padrao {
    static function get($path = null, $config=null){
        if(!empty($path)){
            $path = explode('@',$path);
            // Parte do ficheiro de configuração (adaptado para o exemplo)
            $array = array('mysql'=>array
('host'=>'127.0.0.1','dbname'=>'exemplo','charset'=>'utf8','usuario'=>'root','password'=>''),'outros'=>array());
            //Padrao para o caso de não serem especificados dados externos
            $config = !isset($config) && empty($config) ? $array : $config;
            foreach($path as $part){
                if(isset($config[$part])){
                    $config = $config[$part];
                }
            }
            return $config;
        }
        return false;
    }
    /*
    static function path(){...}
    ...
    */
    
}

In the first method of this class, I created the variable $array as default values for that method, just for this example, they usually don’t even exist in that method, because they are brought from the configuration file, where I store the constant and other values predefined.

Finally, I have this part, where I create an instance of this connection, and return all existing entries in the database, as they are usually done on main pages.

$database = Database::getInstance()->query('exemplo',array('id','>','40'));

if(!Database::erro()){
    foreach($database->resultado() as $object){
    print $object->id . " - " . $object->titulo . "<br/>";
}
} else {
    echo Database::erro();
}

The method erro() was defined as static because I needed access to the value of $_erro from outside this class.

Doubt:

Based on the type of project I intend to build and the features I intend for this project, the standard Singleton is really ideal?

What mistakes have I made yet in this little development?

  • Like, I’ve read these answers over and over, and right now I’m more concerned about compatibility, and whether I’m programming in the right way, taking into account the type of project, especially by "criticism" that this pattern received.

  • 1

    Relax, wear Singleton where you need it and don’t use it where you don’t need it and you’ll be fine. Some classic examples where you might need it: database connection manager and message queue manager.

  • Okay, thanks for the tip, anyway I’m almost done with the general classes, soon I’ll be renewing the layout. Nevertheless, I shall await a possible response based on practical examples.

1 answer

4


OOP

You chose to use PHP because you are probably making an application that is not very complex. Dynamic languages are not very suitable for complex applications, Low-grade gets worse. OOP is also a great paradigm when it really brings real advantages and this occurs a lot in complex applications developed by large teams. OOP in PHP helped a lot with the creation of frameworks existing today. OOP in PHP is more important for most developers to be able to consume than to create.

We’re talking about a language of script interpreted and that will generate execution instances in each call. We are talking about applications that run for a few seconds (or less) and die. They are codes that can be executed (to the extreme) in different ways at each execution.

Dynamic languages require many tests compared to static ones. How many PHP applications are tested correctly? I’m talking about a formal testing method. I’m talking about unit testing, at least. In general those who choose PHP do not want ceremony, do not want to spend time with this kind of thing. Therefore, these languages are called script. They are not called Nterprise.

Will creating a class that will create an instance that will be used in an execution context and will die soon after, without needing to be reused, really necessary? Did the old way of doing these things in PHP giving a include simple (which would also need to opt for the complex way) taking the basic code that will establish the connection is not enough?

What I see is that the developers have lost perspective on what PHP is good at. Perhaps by marketing, perhaps not to be left behind, the language today sells as suitable for large projects. And in fact they can be done in language, but these projects are executed in a fragmented way in a form similar to what was done in the 1960s, in Jobs short.

Singleton

Design Patterns, Like Singleton, they were created to solve complexities where they are needed, not where they were created artificially. And in most cases scripts PHP complexity is artificial, this seems to be the case.

I keep thinking, what if you need to have more than one database connection? Singleton already screwed up, right? Then you will say: "but it is something simple, I will not need more of a connection". Exact. And you already began to realize this with the new question. It doesn’t need any instance because it will run fast and die.

I made a question about this.

An excellent reason to nay use Singleton (implemented right) is to be able to have more than one instance of that object. But if you know that this will not occur (in scripts It’s almost guaranteed you’ll never need it), you can use it. If you can use Singleton you can use something static, or something even simpler than a class. Something static might look like Singleton, but it’s not.

In my opinion the use of OOP in scripts web doesn’t make much sense, at least not in the application itself. It makes less sense to complicate what could be simple.

Some people might say that using Singleton makes testing difficult. It’s a good reason not to use it, but only if the test is carried out. Even though PHP is flexible enough to allow simple testing even without a class. It must exist, but in practice I’ve never seen a PHP code where the person replaces the connection to a database with a mock which facilitates testing. I don’t think I’ve ever seen anyone test the way it should be done in PHP applications. I’ve seen in frameworks, only.

Design Pattern

Design Patterns as the Gang of Four are great for applications Nterprise, not to scripts. Even this site that is not so simple, was developed in static language (by performance and maintenance) but using techniques of script, not OOP and DP. There are engineers there who know what they are doing. They are not using solutions Nterprise for scripts, as is very common, especially in the Java world. This culture is being forced into PHP. PHP is losing its best feature.

If several other mistakes have been made (wrong choice of language, paradigm, exclusion of tests, development methodology, etc.) using Singleton or not will make no difference. Singleton is not so problematic so other things are much worse, and it exists because it is useful. Only some radicals say it is never to use. Can use yes.

The project

It has probably reached a point of development that cannot change everything. But mostly already convinced that OOP is the salvation, the cure for cancer, even in PHP. So use the pattern, it is not ideal for this type of project. But as almost every PHP programmer thinks it is not going to be I will tell not to use. Marketing will beat the scientific criteria, especially in the time of fake news so prevalent..

The mistake is to do something complex in a project that should be simple. But it is not a capital mistake, you will manage well with it.

Having said all that, the implementation is wrong because it is taking responsibility for doing the query (very limited), which hurts the principle of single responsibility. Is it going to cause a problem? Probably not. Which confirms what I said above. It is a lot of solution to little problem.

Although violating the SRP would make some sense (in a script) encapsulate the connection in the configuration class (which needs to be slightly different from what was used). It would make as much sense as not "organizing" it all this way and doing something simpler.

But for any methodology that is adopted it is necessary to understand well what is doing. And the less you understand all aspects of development, the less you should opt for more complex solutions, even if they fit. What is not the case of scripts websites on "small websites".

  • Thanks again for the excellent explanation, and the time. When you said "do not use Singleton (right implemented)", you said it was right rewrite the pattern to accept more than one instance ? And when you said " can’t change everything", it is quite likely that I explained myself badly in the question, but this is all a live test, so live demonstration of the problems critical points that the project can present in a productive environment.

  • "already convinced that OOP is the salvation" - Apparently it’s another misunderstanding, perhaps and you’ve often seen me say that "rarely" use OOP/POO to write web applications, but one thing is to know how to use the right tool for the right job (use a hydraulic press when you can use your hands) which is not what happens here. Starting from the beginning, the basic meaning, and the use of classes is very clear, and speaking of classes is basically talking about OOP.

  • I cannot say that I disagree with a large part of your reply, but it is also unwise to say that I agree, because there are too many unknowns to date remaining.

  • In the background, if you are going to analyze my question, it is very objective, however I imagine that I made some mistakes in the explanatory part, where I seem to omit most of my goals with this implementation, and the project itself.

  • What I really wanted with the implementation of this standard(s), was to perform tests to know how they would behave in a productive environment in this same application. This meeting some principles of maintainability for the system to be integrated. Organize and centralize tasks,and obvious increase in functionalities.

  • In quoting a lot of pros and cons in your reply, it was partly rude of me, but denying the truth is even worse, and above all, I’m not being ungrateful, on the contrary, I’m really grateful for your answer. It’s good to know that some people still care.

  • 1

    It would be better to allow other instances if you needed to have them. There are situations that this is necessary. But as I said on the whole, this is exaggeration for scripts. I think you are using hydraulic press to make pasta :) or OOP p/ make scripts. But there are a lot of people who disagree with me and do the same. It’s a common mistake for people to think that using classes, they’re using OOP. It is very difficult for you to simulate maintenance situations without being doing real. And it is difficult to experience in real situation. It was not rude.

  • The original code is about 8 times smaller than the one I’m writing, and it’s procedural, function-based, and it works normally, and I can apply modifications without minimal effort. I believe I know exactly what you’re talking about, but it’s like a necessary evil to the current situation, if you know what I mean.

  • This is what I’m talking about :) If everyone had that perception.

  • First of all, "I’m sorry," because the answer was well-founded, but there’s still no answer if you know what I mean, you certainly wrote it with the best of intentions, but it wasn’t what I expected as an answer, apart from the fact that I would probably be the only one to benefit from this question/answer, I will unfortunately have to close the question.

Show 5 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.