Private or protected class in PHP

1

Is it possible to create a private or protected class in PHP in order to allow access to its variables and functions only to other specific classes?

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

connection.php

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

user.php

<?php
require_once "conexao.php";

class DAO_usuario {
    private $conexao = null;

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

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

Note: I do not use nor will I use frameworks , pure PHP only

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

    
asked by anonymous 22.03.2018 / 20:59

4 answers

5

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

Even in other languages to say who can call a class is usually not possible, other than putting their visibility in the same package, then it does not say who can access, but says where it can be accessed.

PHP does not have anything like it, after all It's a script language. And in scripts it is easy to administer the use of classes (although I find strange scripts to have classes). If it's something complex that really needs this control, it's not scripts , and then PHP does not seem to be the right language.

In no language is there a protected class.

You can not protect a class, so you can not say how to do this, you can only say that it is not possible. So the reward was put without need, unless the question and the reward are not clear.

    
22.03.2018 / 21:31
1

ATTENTION HERE

From OOP's point of view, what you want to do does not make much sense and @Maniero's answer is correct. Really consider rethinking what you are trying to do.

NOT VERY WARNING HERE

Now, since PHP gives us many "alternative solutions": trollface :, 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 issues within your application.

Files in the directory:

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

This "alternative" is to force the implementation of an interface to use a class that contains the connection to the database.

DAO interface:

<?php

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

?>

AbstractDAO 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 (Class valid to use the connection to the base):

<?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();
        }
    }

?>

InvalidDAO class (Class that should not use the 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 validation:

link

link

    
12.04.2018 / 18:25
0

Unable to declare a private class. However you can declare a method as private, it will only be possible to access it by instantiating the class of the method. It could be done up by the constructor using private method or depending on the protected need.

private function conexao($user,$pass,$url)
    
11.04.2018 / 00:55
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, no one besides the outer class and whomever you extend it will have access.

You could still do this better by having an abstract DAO class with this constructor, with DAO_usuario and other DAOs extending it and sharing the same single connection / "private class".

    
11.04.2018 / 16:15