Private or protected class in PHP

Asked

Viewed 938 times

1

You can create a private or protected class in PHP to allow access to its variables and functions only to other specific classes?

Applying: I have a class where I create a connection with the database and wanted to allow access to this class only to other classes that perform CRUD in the database

php connection.

<?php
class Conexao extends Mysqli {
    private static $conexao = null;

    function Conexao($servidor, $usuario, $senha, $banco) {
        parent::__construct($servidor, $usuario, $senha, $banco);
    }

    public function __destruct() {
        self::$conexao->close();
    }

    public static function getConexao() {
        if(!isset(self::$conexao)){
            self::$conexao = new Conexao("localhost", "usuario", "senha", "nome_banco");

            if (mysqli_connect_error()) {
                die('Erro ao conectar ao banco de dados (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
            }

            if (false === self::$conexao->set_charset('utf8')) {
                die("Error ao usar utf8");
            }
        }
        return self::$conexao;
    }
}

php user.

<?php
require_once "conexao.php";

class DAO_usuario {
    private $conexao = null;

    function __construct() {
        $this->conexao = Conexao::getConexao();
    }

    public function cadastrar_usuario($nome, $usuario, $senha, ...) {
        // [...]
    }
}

Observing: I neither wear nor will wear frameworks, only pure PHP

The focus of the question is OOP, but it would be interesting to comment on the procedural style equivalent

  • 1

    you can use php extends this way the class will become part of the other one and any class that tries to do include or use name space cannot the code gets more or less like this classBanco extends outraclass >> http://php.net/manual/en/Reflection.extending.php

  • @Marcosbrinnerpikatoons in the case then I would class DAO_usuario extends Conexao, class DAO_produto extends Conexao, ...?

  • Members declared as protected can only be accessed in the reporting class and its heirs classes, those declared as private can only be accessed in the class that defines the private member.

  • @Fabianomonteiro can exemplify this in a reply?

  • So my comment is based on php.net. A full explanation you will find here: http://php.net/manual/en/language.oop5.visibility.php .

4 answers

5


PHP does not support private classes, and from what I understand it is not even what you want.

Even in other languages saying who can call a class isn’t usually possible, except by placing its visibility in the same package, so it doesn’t say who can access it, but it does say where it can be accessed.

PHP has nothing like, after all It is a language of script. And in scripts it is easy to manage the use of classes (although I find it strange scripts have classes). If it’s something complex that really needs this control, it’s not scripts, and then PHP seems not to be the proper language.

In no language is there a protected class.

There’s no way to protect a class, so there’s no way to tell you how to do this. So the reward was placed unnecessarily, unless neither the question nor the reward is clear.

  • Ok, I can’t declare the private class but I can declare your methods and variables, in case you have to allow access to a method, only by some classes?

  • 1

    No, if neither class is possible, even less methods. Of course, you can prevent access to any class, or only to the classes you inherit from it, but if you make an inheritance just because of this, you’re doing something very wrong. I already wonder (but do not say) if Connection should inherit from Mysql.

  • Thank you, and how could I "prevent access to any class"?

  • When you say that "PHP does not support private classes", this means that it also does not support protected classes (protected) right?

  • About "but if you make an inheritance just because of this you’re doing something very wrong.", could explain a little more?

  • 1

    You can do an immense gambit with validations on __construct, in order to return the instance only pass the validation. But it is only a hypothesis and totally gambiarrosa, does not recommend. What @Maniero says makes a lot of sense, if this is crucial to your project, try to implement a language that meets the requirements naturally.

  • 2

    @Guilhermecostamilam inheritance must be made when you need to extend a class, not to protect something. It needs to have a direct relationship, the derivative needs to be the same as the base, with something more. The whole question is very simple: can not protect as you want, it makes no sense to want it, has no utility, is not conceptually correct, especially in PHP which is a language of script. In some languages that allow to produce complex solutions it is possible to protect for a specific group, but not individually, except with external tools created by you.

  • @Maniero knows some way to prevent (or at least hinder) a class or function from being instantiated in any file?

  • @Guilhermecostamilam functions are not instantiated. Classes can be prevented from being instantiated, but it is not what you ask in the question. See abstract classes.

  • Okay, but is it possible that someone can create connections where they shouldn’t and access my database since my class that creates this connection is public? Just for testing, from the links and the answer of @Tommelo I created an abstract connection class and extended it in a class with DAO I believe that the security difference is insignificant (if it exists). The idea was just to try to protect more my connection to the bank is not something essential to the application

  • No, this is not possible, you are worried about the wrong things, security is something else, nothing this will give security. Again what you want is not possible in any language, even less in PHP.

Show 6 more comments

1

ATTENTION HERE


From the OOP point of view what you want to do doesn’t make much sense and @Maniero’s response is correct. Really consider rethinking what you’re trying to do.

NOT MUCH ATTENTION HERE


Now, since PHP allows us many "alternative solutions":Rollface:, I’ll leave here an "alternative" (which should not be used) that might give you some other idea.

Remembering that this "alternative" guarantees absolutely nothing of what you are trying to do and can still put problems within its application.

Files in the directory:

dao.php
abstract-dao.php
user-dao.php
invalid-dao.php
test.php

This "alternative" consists in forcing the implementation of a interface for the use of a class containing the database connection.

DAO interface:

<?php

    interface DAO
    {
        public function insert($entity);
        public function update($entity);
        public function delete($entity);
    }

?>

Abstract class:

<?php    

    abstract class AbstractDAO
    {
        private $conn;
        private const SHOULD_IMPLEMENT = "DAO";

        public function __construct()
        {
            $called_class = get_called_class();
            $implements_array = class_implements($called_class);

            if (!in_array(self::SHOULD_IMPLEMENT, $implements_array))
            {
                throw new Exception("DAO interface must be implemented");
            }

            // inicializa a conexão...
            $this->conn = "Conexão Válida\n";
        }

        protected function getConnection()
        {
            return $this->conn;
        }
    }

?>

Userdao class(Valid class to use base connection):

<?php

    require_once "abstract-dao.php";
    require_once "dao.php";

    class UserDAO extends AbstractDAO implements DAO
    {
        public function __construct()
        {
            parent::__construct();
        }

        public function insert($entity)
        {
            echo parent::getConnection();
        }

        public function update($entity)
        {
            echo parent::getConnection();
        }

        public function delete($entity)
        {
            echo parent::getConnection();
        }
    }

?>

Invalid class(Class not to use connection):

<?php

    require_once "abstract-dao.php";
    require_once "dao.php";

    // classe não implementa a interface DAO

    class InvalidDAO extends AbstractDAO
    {
        public function __construct()
        {
            parent::__construct();
        }

        public function try_get_connection()
        {
            echo parent::getConnection();
        }
    }

?>

Testing:

<?php

    require_once "user-dao.php";
    require_once "invalid-dao.php";

    $userDAO = new UserDAO();
    $userDAO->insert("qualquer coisa");

    // exception
    $invalidDAO = new InvalidDAO();
    $invalidDAO->try_get_connection();

?>

For more information on the functions used for the validation:

http://php.net/manual/en/function.get-called-class.php

https://secure.php.net/manual/en/function.class-implements.php

0

It is not possible to declare a private class. However you can declare a method as private, you can only access it by instantiating the method class. It could even be done by the builder using private method or depending on the protected need.

private function conexao($user,$pass,$url)

0

One possibility is to use Anonymous classes:

<?php

class DAO_usuario {
    static protected $conexao = null;

    public function __construct() {
        if (self::$conexao) {
            return;
        }

        self::$conexao = (new class($servidor, $usuario, $senha, $banco) extends Mysqli {
            public function __construct($servidor, $usuario, $senha, $banco) {
                parent::__construct("localhost", "usuario", "senha", "nome_banco");

                if (mysqli_connect_error()) {
                    die('Erro ao conectar ao banco de dados (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
                }

                // https://en.wikipedia.org/wiki/Yoda_conditions !
                if (false === $this->set_charset('utf8')) {
                    die("Error ao usar utf8");
                }
            }
        });
    }

    public function __destruct() {
        self::$conexao->close();
    }

    public function cadastrar_usuario($nome, $usuario, $senha) {
        // [...]
    }
}

For all intents and purposes you have a private class there, no one but the outside class and whoever extends it will have access.

You could still better it by having an Abstract DAO class with this constructor, being that DAO_usuario and other Daos would extend it and share the same single connection/"private class".

Browser other questions tagged

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