I have a connection class to the sqlClass database and in it I registered the query_exec method that executes the SQL queries.

I also have another pageNavClass class and it has a SQL parameter to count the number of cells in a particular table. (in general, it is planned to use any table), and there is also a usersClass user usersClass inherited from sqlClass , in the usersClass user usersClass there is a listAllUsers method that should return the result of all counted cells to the specified one. range. through the declared pageNavClass in it.

A question how to connect two classes usersClass and pageNavClass , without using inheritance. I need to get the query_exec method from sqlClass so that I can use SQL queries in naveNavClass declared for example in usersClass ?

UPD!

 // MySQL Connection connection.php class Connection { private $connect_result; function Connection(){ require_once ('includes/config.inc.php'); $dsn = "mysql:host=".DBHOST.";dbname=".DBNAME.";charset=".CHARSET; $opt = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); try { $this->connect_result = new PDO($dsn, DBUSER, DBPASS, $opt); } catch (Exception $e) { die("Error! " . $e); } /* Исполняем все необходимое, что нужно обсолютно везде */ $this->loadLanguage(); $this->users_online(); $this->AuthStatus(); //var_dump(AUTH_STATUS); } public function getCon() { return $this->connect_result; } // метод выполнения запроса SQL !!! public function queryExec($sql, $data=false){ $stmt = $this->getCon()->prepare($sql); if (!$data) $stmt->execute(); else $stmt->execute($data); return $stmt; } } 
 class PageNav { function navigation ($sql) { // Переменная хранит число сообщений выводимых на станице $num = 25; // Извлекаем из URL текущую страницу $page = 1; if (!empty($_GET['page'])) { $page = intval($_GET['page']); if ($page < 1) { $page = 1; } } // Определяем общее число сообщений в базе данных $result->queryExec("SELECT COUNT(*) FROM post")->fetch(); // Находим общее число страниц $total = intval(($posts - 1) / $num) + 1; // Определяем начало сообщений для текущей страницы $page = intval($page); // Если значение $page меньше единицы или отрицательно переходим на первую страницу // А если слишком большое, то переходим на последнюю if(empty($page) or $page < 0) $page = 1; if($page > $total) $page = $total; // Вычисляем начиная к какого номера следует выводить сообщения $start = $page * $num - $num; // Выбираем $num сообщений начиная с номера $start $result->queryExec("SELECT * FROM post LIMIT $start, $num"); // В цикле переносим результаты запроса в массив $postrow while ( $postrow[] = mysql_fetch_array($result)) echo "<table>"; for($i = 0; $i < $num; $i++) { echo "<tr> <td>".$postrow[$i]['name']."</td> <td>".$postrow[$i]['time']."</td></tr> <tr><td colspan=\"2\">".$postrow[$i]['text']."</td></tr>"; } echo "</table>"; } } 
 // users.class.php class Users extends Connection{ public function listAllEventUsers() { $this->navPage = new PageNav(); $sql['count'] = "SELECT COUNT(*) FROM users_for_events"; // $start, $num $sql['fetch'] = "SELECT * FROM users_for_events LIMIT ?, ?"; $this->navPage->navigation($sql); return ; // array with all users } } 
  • 2
    Minimally, I suggest you lay out your classes so that you can visually understand what you are doing there .... Secondly: you should not have any heirs to the sqlClass class that works with the database and its connections .... This is a fanaticism and perverted. Especially not related to him in any way the class of users .... sqlClass you should be final .. - Alexey Shimansky
  • updated above ... - jcmax
  • @jcmax, you'd better have led the UML class diagram ( - Dmitriy Simushev

4 answers 4

You have wrongly designed your system right from the start. The problem is that breaking the functionality into classes in the way that you did nothing but a headache in the medium and long term, you will not get.

How would I approach the realization of your task:

  1. It is necessary to break the whole system into several layers. Usually, a data access layer, a business logic layer and a presentation layer are distinguished. Each of the layers is responsible for one of the common tasks assigned to the system.

  2. In the business logic layer, a Domain Model is created . In your case, this is the User object.

  3. In the data access layer, a decision is made on how to display the domain classes on the database. In the simplest case, I would recommend using the Active Record implementation of the template. This slightly erases the boundaries between the layers of the application (at the same time violating SRP ), but it allows you to make the code as simple as possible.

    The entire logic of executing SQL queries is transferred to the QueryRunner class (your sqlClass ), which, in essence, is a wrapper for PDO.

    Here, the save and delete functions are added to the user object.

  4. I would take the logic of selecting users into a separate hierarchy of classes UserFinder . This will allow, on the one hand, to remove part of the logic from the User class, and on the other, get rid of the magic of static search methods (together with the implementation of Singleton in sqlClass ).

  5. Everything related to the display of objects must be moved to a separate layer of the view. There can be quite a few options, I will not go into the details.

So you should get the following class structure:

enter image description here

Sample code linking all parts of the system together:

 <?php $sql_runner = new SqlRunner(new \PDO()); $user_finder = new UserFinder($sql_runner); $users = $user_finder->findAllPaginated(3, 10); // В реальном приложении, генерация HTML кода должна происходить в // слое представления. Здесь же, для простоты, я просто использую часть // PHP-файла как шаблон. (Никогда не делайте так!) ?> <ul> <?php foreach($users as $user): ?> <li><?php echo $user->getLogin(); ?></li> <?php endforeach; ?> </ul> 

As you can see, there is no inheritance at all, but only composition . In general, it makes sense to use inheritance only when there is a direct relationship of kinship between the entities. In all other cases it is more correct to use the composition.

The composition allows, on the one hand, to keep unrelated functionality in completely different class hierarchies, and on the other, to combine the interacting parts of the system at the object level where necessary.

Comment:

The above Model Domain and Active Record are not the only approaches to solving your problem. There are many other design patterns that may be useful. Among them it is worth noting:

  • Almost understood, but still thanks in the process I will understand, I think! - jcmax

You just need to use the object of class sqlClass in the classes usersClass and pageNavClass .

For starters, you can go the beaten path and use the class sqlClass as a "alone" (Singleton).

And you can immediately write through DI (Dependency Injection). Create ext. a class with the "registry" pattern (Registry) and through it, wherever you get the necessary object to work with the database.

  • With proper implementation of DI, none of the objects in the system should depend on the container of objects. At least in such a simple class scheme. - Dmitriy Simushev

You need to use traits . Introduced with PHP 5.4

 trait someName { function query_exec() { } } class pageNavClass { use someName; /* ... */ } class usersClass { use someName; /* ... */ } 

In simple terms, they embed methods in classes, somewhat similar to multiple inheritance. Those. describe the method in the trait, and can use it in any class you like

Using telepathy:

  1. Try to make the methods static and then they can be called from everywhere.
  2. Inheritance
  3. Implement functions as a trait and connect to any class via use
  4. What prevents to create an object of two classes in the third and call the necessary functions?