Добра практика ли е ?

dakata__92

Super Moderator
Добра практика ли е да подаваш на __construct($db) ?

User.php
PHP:
class User{
	private $db;
	
	public function __construct($db){
		$this->db = $db;
	}
}

index.php
PHP:
<?php
include "DB.php";
include "User.php";

$u = new User($db);

?>

DB.php
PHP:
<?php
$DB_HOST = 'localhost';
$DB_USER = 'root';
$DB_PASS = '';
$DB_NAME = 'oop';
$db = new mysqli($DB_HOST, $DB_USER, $DB_PASS, $DB_NAME);
if($db->connect_errno > 0){
	die("Unable to connect to database [".$db->connect_error."]");
}
?>
 
http://williamdurand.fr/2013/07/30/from-stupid-to-solid-code/#tight-coupling

Tight coupling, also known as strong coupling, is a generalization of the Singleton issue. Basically, you should reduce coupling between your modules. Coupling is the degree to which each program module relies on each one of the other modules.

If making a change in one module in your application requires you to change another module, then coupling exists. For instance, you instantiate objects in your constructor's class instead of passing instances as arguments. That is bad because it doesn't allow further changes such as replacing the instance by an instance of a sub-class, a mock or whatever.

Tightly coupled modules are difficult to reuse, and also hard to test.

Какво означава това. Ще си построиш User с методите на DB. В един момент ще искаш да смениш DB я с PDO, я с някое API. Сам разбираш, че целия User отива на кино :)

Ако разбираш руски, към горното прочети и това.
 
В общи линии идеята на горното е да не кодиш така, че промяна на едно нещо да доведе до промяна на друго нещо. Гледай нещата, които правиш да са максимално необвързани.

Ако подаваш базата данни като параметър, какво правим, ако се наложи да използваш файл по някое време, ще пренапишеш класа User?
 
HunterEx каза:
В общи линии идеята на горното е да не кодиш така, че промяна на едно нещо да доведе до промяна на друго нещо. Гледай нещата, които правиш да са максимално необвързани.

Ако подаваш базата данни като параметър, какво правим, ако се наложи да използваш файл по някое време, ще пренапишеш класа User?
Ок но това не отговори на по-горният ми въпрос за наследяването.
 
Същото важи и за наследяването, да предположим, че User надледява DB, ако трябва да го промениш да използва File, ще направиш така, че User да наследява File, тоест това отново ще доведе до преработване на User.

Мисли на по-високо ниво, направи си клас, който да има методи за запис, изтриване, модифициране и т.н. (тук много добре се вписват интерфейсите) и когато се наложи промяна просто правиш нов клас, който да имплементира/екстендва направения клас/интерфейс. Препоръчвам ти за изучаването на ООП, да използваш изцяло ООП език като Java или C#, много по-бързо и лесно ще навлезнеш в идеите и шаблоните. Като гледам кода от първия коментар още не си се оттърсил от процедурния код.

Не претендирам, че познавам ООП прекалено добре, но мислиш ли, че User има допирни точки с BD, че да вкарваш наследяване?
 
До тук мисля, че се справих. Сега въпросът ми е как да подам на User.php - на неговият клас на метода public function login(){} базата с данни ? Трябва ли да наследи клас DB или в индекса нещо трябва да се подаде?


DB.php
PHP:
<?php
class DB{
	
	private static $instance = Null;
	private $results;
	private $db;
	
	private function __construct(){
	
	}
	public static function getInstance(){
        if (self::$instance == Null){
            self::$instance = new self;
        }
        return self::$instance;
    }
	
	public function connect($DB_HOST, $DB_USER, $DB_PASS, $DB_NAME){
		$this->db = new mysqli($DB_HOST, $DB_USER, $DB_PASS, $DB_NAME);
		if($this->db->connect_errno > 0){
			die("Unable to connect with database [<b>".$this->db->connect_error."</b>].");
		}
	}
	
	public function query($sql){
		return $this->db->query($sql) or die("SQL error at line: ".__LINE__." in ".__CLASS__);
	}
	
	public function close(){
        if($this->db){
            $this->db->close();
		}
    }
}
?>

index.php
PHP:
<?php

include "config.php";
include "DB.php";
include "User.php";

if(isSet($_POST['submit'])){
	
	$user = $_POST['user'];
	$pass = $_POST['pass'];
	$db = DB::getInstance();
	$db->connect(DB_HOST,DB_USER,DB_PASS,DB_NAME);
	$db->query("SELECT * FROM `user` WHERE name='$user' and pass='$pass'");
	
	
}
?>
<html>
<head>
<meta http-equiv='content-type' content='text/html; charset=UTF-8' />
</head>
<body>
<form method='POST' action=''>
<br><input type='text' name='user' value='Daniel'/>
<br><input type='text' name='pass' value='123456'/>
<br><input type='submit' name='submit' value='Бутон'/>
</form>
</body>
</html>

config.php
PHP:
<?php
define('DB_HOST','localhost');
define('DB_USER','root');
define('DB_PASS','');
define('DB_NAME','oop');
?>

User.php
PHP:
<?php
class User{
	private $db;
	private $id;
	private $user;
	private $pass;
	
	public function __construct(){
	}
	
	public function login($user,$pass,$db){
		$result = $db->query("SELECT * FROM `user` WHERE name='$user' and pass='$pass'") or die("SQL error at line: ".__LINE__." in ".__CLASS__);
		if($result->num_rows > 0){
			while($row = $result->fetch_assoc()) {
				$this->id = $row['id'];
				$this->user = $row['name'];
				$this->pass = $row['pass'];
				echo $row['id']." ".$row['name']." ".$row['pass'];	
			}
			
		}
		else {
			echo 'Сгрешен потребител или парола. ';	
		}
	}
	
	public function logout(){
		echo '<br>Logout';
	}
}
?>
 
Не е нужно да го наследяваш, просто си правиш инстанция на класа ДБ в класа ЮЗЪР. Понеже ДБ ти е сингълтон то ЮЗЪР ще работи със същата инстанция, както и навсякъде другаде където си я викаш.
 
teroristd каза:
Не е нужно да го наследяваш, просто си правиш инстанция на класа ДБ в класа ЮЗЪР. Понеже ДБ ти е сингълтон то ЮЗЪР ще работи със същата инстанция, както и навсякъде другаде където си я викаш.
Може ли малък код за разяснение.
 
дака, тоя сингълтон нищо не прави. За какво изобщо викаш get instance, след като в index пишеш $db->connect??? Много грешно... тия неща трябва да стават в самия клас.
 
djman каза:
дака, тоя сингълтон нищо не прави. За какво изобщо викаш get instance, след като в index пишеш $db->connect??? Много грешно... тия неща трябва да стават в самия клас.
Така ли? Може ли код за да видя какво имаш предвид. Уча се и искам още в началото да си направя правилните практики за сигурност и прочие, което ще рече, че въпросите са ми много глупави. :D
 
Всъщност в твоя случай просто си викаш логин функцията от юзър в индекса, където си си направил конекцията и тя ще си сработи.
 
teroristd каза:
Всъщност в твоя случай просто си викаш логин функцията от юзър в индекса, където си си направил конекцията и тя ще си сработи.
Аз кода го подкарах, но нещо не ми вдъхва доверие, че това е оптимизиран начин. Нямам доверие на кода, който пиша сам :D
 
Как се учиш? Четеш ли, бях ти дал 2 линка за SOLID код...
Ти човек пишеш код, без да мислиш. За теб ООП е просто по-различен синтаксис, не е ли така? :D
 
djman каза:
Как се учиш? Четеш ли, бях ти дал 2 линка за SOLID код...
Ти човек пишеш код, без да мислиш. За теб ООП е просто по-различен синтаксис, не е ли така? :D
Ами не но принципно от толкова много уроци, които прочетох се обърквам. Един казва, че в конструктора не трябва да има код и да е private. Втори пише, че това не е така и конструктора трябва да е прайвът и да има код вътре. Трети обяснява, че трябва да си напишеш методи за всички INSERT UPDATE SELECT или DELETE. Някой обясняват да не се подават в класът нещата така :
PHP:
<?php
class DB{
	
	private $DB_HOST = 'localhost';
	private	$DB_USER = 'root';
	private	$DB_PASS = '';
	private $DB_NAME = 'oop';

Друг обяснява да се използва config с define и да ги ползвам като константи.

Е на кой да вярвам? Хиляди уроци и всеки си противоречи. Прочетох всичко което ми е дадено препрочитам и кода и прочие и чичо Гугъл, но за една връзка с база данни никъде не срещнах нещо което да ми вдъхне доверие. Сингълтон си е цял политон с тези разновидноти. Не се оплаквам, а питам. Прерових и форума за стари теми но не намерих най-удобните практики за създаване на връзка с база и прехвърлянето и към различните класове, които имат нужда от нея. Че аз мога да си направя една нормална процедурна свръзка и после само да си я инклудвам... Искам да се науча, и правя връзка с базата, но сам виждам, че не е правилна. :?
 
Това djman по-правилно ли е !?

DB.php
PHP:
<?php
class DB{
	private static $instance = Null;
	private $results;
	private $db;
	
	private function __construct(){
		$this->db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
		if($this->db->connect_errno > 0){
			die("Unable to connect with database [<b>".$this->db->connect_error."</b>].");
		}
	}
	public static function getInstance(){
        if (self::$instance == Null){
            self::$instance = new self;
        }
        return self::$instance;
    }

	
	public function query($sql){
		$query = $this->db->query($sql) or die("SQL error at line: ".__LINE__." in ".__CLASS__);
		return $query;
	}
	
	public function close(){
        if($this->db){
            $this->db->close();
		}
    }
}
?>

Index.php
PHP:
<?php

include "DB.php";
include "User.php";
include "config.php";

$db = DB::getInstance();
$u = new User();

if(isSet($_POST['submit'])){
	
	$user = addslashes($_POST['user']);
	$pass = addslashes($_POST['pass']);
	if(!empty($user) && !empty($pass)){
		$query = $db->query("SELECT * FROM `user` WHERE name='$user' and pass='$pass'");
		$u->login($query);
	}

}
?>
<html>
<head>
<meta http-equiv='content-type' content='text/html; charset=UTF-8' />
</head>
<body>
<form method='POST' action=''>
<br><input type='text' name='user' value=''/>
<br><input type='text' name='pass' value=''/>
<br><input type='submit' name='submit' value='Бутон'/>
</form>
</body>
</html>
 
djman каза:
А грешно ли е да се направи това?
PHP:
<?php
class DB{
        
        private $DB_HOST = 'localhost';
        private $DB_USER = 'root';
        private $DB_PASS = '';
        private $DB_NAME = 'oop';

PHP:
private function __construct(){
		$this->db = new mysqli($this->DB_HOST, $this->DB_USER, $this->DB_PASS, $this->DB_NAME);
		if($this->db->connect_errno > 0){
			die("Unable to connect with database [<b>".$this->db->connect_error."</b>].");
		}
	}

Препоръчително ли е или не ? Ако е не каква е правилната практика.
Втори въпрос. Ако друг клас например User.php има нужда от връзка с базата данни как НАЙ-ПРАВИЛО и препоръчително да направя връзката?

Трябва да инклудна класът DB в User и да го наследя ли? Да подам връзката на базата през конструктора на User.php или има по-добри варянти? С код ще ми стане много по ясно (по възможност). :)
 
Разгледай какво е Repository.

Това е правилният вариянт.

Вместо MemoryStorage, ще направиш DatabaseStorage и ще използваш DB класът си в него.

Ако нещо не ти е ясно, питай.
 
Ок разбрах какво имаш предвид, но какво общо има това с базата? Трябва да напиша втори клас в който да сетвам и махам базата ли? Или така да си я прехвърлям през класовете посредством методи от типа сет(тук) и гет()? Още в конструктора на последният ми код правя:
PHP:
	private $db;
	
	private function __construct(){
		$this->db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
		if($this->db->connect_errno > 0){
			die("Unable to connect with database [<b>".$this->db->connect_error."</b>].");
		}
	}

Трябва ли да направя:
PHP:
 public function getDb()
{
return $this->db;
}

Не виждам смисъла да го правя в този клас. Вероятно си имал предвид в User.php да направя такова сетване но все пак това с прехвърлянето ми се вижда странно. Ако имам нужда от конекция с базата в класс User.php с кодовете, които дадох до момента как ще стане прехвърлянето на базата, осъществяването на връзката? Глупави са ми въпросите сам се сещам два три възможни начина и врътки, но как е прието в практиката да се прави. Все пак затова правя клас DB, който да извършва операцииите с базата а вече обработката на информациятя е съвсем друго нещо.
 

Back
Горе