OOP - Въпроси , проблеми , отговори

StormBreaker каза:
Не разбрах нищо от това, което написа. Какво общо има кода, който си пуснал в началото с текста?
Опитах се да обясня че класа Security и функцията hash са напълно безмислени.

Ето ти пример за scalar value:
Код:
$dbc->select("table", "MAX(ID)");
Според теб нужно ли е да се прави отделна функция за това в модела, или може да се извика директно от конкролера.
 
Не погледнах дали е споменато вече,но е голямо предимство да се пише на ООП ,когато се работи в екип.
 
FFDP каза:
StormBreaker каза:
Не разбрах нищо от това, което написа. Какво общо има кода, който си пуснал в началото с текста?
Опитах се да обясня че класа Security и функцията hash са напълно безмислени.

Не са безсмислени, както не е безсмислено да правиш клас Database, който да ползва готови функции като query, connect и т.н.
Идеята тук е като ти потрябва да смениш хеширащата функция пипаш просто този метод, не навсякъде дето си го ползвал.
Може би щеше да е по-добре тази функция да е статична в случая. Няма смисъл от нов обект при положение, че няма никакво вътрешно състояние.

Ето ти пример за scalar value:
Код:
$dbc->select("table", "MAX(ID)");
Според теб нужно ли е да се прави отделна функция за това в модела, или може да се извика директно от конкролера.

Нужно е. Иначе не пишеш качествен код, защото смесваш компонентите на MVC. То ако гледаш просто на нещата защо ти е изобщо модел, като можеш всичко да си вземеш в контролера?

Разделението на ролите на кода е много важно нещо, за да пишеш качествен код, който може да се поддържа от много хора. Контролера не трябва да знае какво се случва в БД и в модела. Това трябва да го знае само самия модел.

Тук въпроса е не какво ще ти е по-удобно, а как ще разделиш кода на смислови части, независими една от друга до колкото е възможно. Иначе пишеш процедурен код в класове и правиш нещо, което като се разрастне ще е невъзможно за поддръжка. Като ползвай MVC се придържай към неговите идеи.

То разликата между заявка в контролера и заявка във вюто е мнооого тънка. Защо за всяко нещо трябва да предаваш нови променливи като може директно да набиеш заявката във вюто? Логиката е същата. Реално можеш който и да е код да го бухнеш където и да е. Въпроса не е дали ще работи и дали ще ти е по-лесно, а дали пишеш код, който после ще се поддържа лесно или нещо, което има връзки с БД навсякъде и ако (боже опази) трябва да се променят таблиците в БД. Тогава вместо да промениш само модела ще трябва да пускаш search в целия проект, защото не знаеш кой къде е правил заявки "за по-лесно".
 
MVC http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller, е много добър design patterns, има големи спорове къде трябва да се съдържа логиката дали в контролера или в модела. Аз съм на мнение, че в модела трябва да става почти всичко. Един потребител, бе написал, че на php не може голям проект, не е вярно, просто той не го прави както трябва, а искам да отбележа,че когато се намеси и ORM в php нещата стават далееч по - добри.
Но ако имаш connection на повече от едно db, OOP-то е решението.
singleton това е просто един метод който в някой моменти върши чудеса, но той не е решение да всичко. Трябва да знаеш кога ти трябва и кога не.
Един съвет не пренаписвайте php sмисал ако md5 е функция и ти просто връщаш
function hash($str){
return md5($str)
}
то наистина няма смисъл, но ако има логика в него

function hash($str){
..... логика
return md5($логика)
}
то тогава има смисъл.
 
macmen каза:
Един съвет не пренаписвайте php sмисал ако md5 е функция и ти просто връщаш
function hash($str){
return md5($str)
}
то наистина няма смисъл, но ако има логика в него

function hash($str){
..... логика
return md5($логика)
}
то тогава има смисъл.

Това не е пренаписване на PHP. Това е пренаписване на PHP
Това е просто абстрахиране от хеширащата функция. Ако имам тази функция като ми потрябва кода да ползва друга хешираща функция просто променям този метод и всичко работи. Ако на 20 места по различни файлове пише md5 при един голям проект ще ти е мъка да промениш всичко без да бъгнеш нещо или да пропуснеш нещо.
 
Така искам да питам дали съм разбрал правилно какво представлява Interface.

Interface казва на класът, в който го имплементира ме какви функций трябва да има този клас така ли?
 
Jorko каза:
Така искам да питам дали съм разбрал правилно какво представлява Interface.

Interface казва на класът, в който го имплементира ме какви функций трябва да има този клас така ли?
Да, нещо такова...
Представи си че имаш интерфейс : player със следните клас данни :
private $hpMax;
private $hpCurent;
private $manaMax;
private $manaCurent;
private $armor;

И имаш следните методи:
public function hpEnter($hp,$type) {}
public function manaEnter($mana,type){}


Тези неща, ще искаш да ги има в класа NonPlayerCharecter.
Също и тези неща ще ги има и в PlayerCharecter.

Главно се използва , за да зададеш на някой да следва някаква твоя схема. Реално NPC-то и Playera имат еднакви структори. И двете имат живот, мана , броня.
Затова създаваш двата метода , където $type примерно е положителен или отрицателен знак ( за лекуване положителен , и отрицателен за вкарване на някаква вреда.)


След като ги имплементираш , ще трябва да си ги създадеш какво да вършат. Тъй като примерно NPC-то може да има 20% dmg reduce ако е под 30 % живот.
А пък играча , може да има пасивна "магия" която не позволява да му се вкара DMG който повече от 1/3 от макс живота.
 
Значи правилно си мисля :D

Добре и друго искам да питам, защо да ползвам exception след като мога да ползвам echo или print, или да си създам масив с грешките и да го викам после?
 
index каза:

Сигурно ще ме помислите за дразнещия човек, който само поправя хората, но какво да се прави :D

Интерфейса не може да има член-данни. Не може да има и private/protected методи. Трябва само да казва някакви public методи.

@Jorko Идеята на интерфейсите (в PHP) е просто да задължиш някакъв клас да има някакви методи. Можеш да имаш няколко класа, имплементиращи един интерфейс и като имаш обект от един от тях дори не те интересува кой точно клас ползваш. Щом имплементира интерфейса => има методите, които ползваш => ти върши работа.
 
Мен ме дразни , това ,че ме подминаваш в FMI като пътен знак, а аз говоря на стената " Ей здравей ! "
:)
Просто исках да му го илюстрирам с пример.Но , и твоят начин с думи , става :) Всеки трябва да преоткрие своят начин на разбиране за нещата :)
 
index каза:
Мен ме дразни , това ,че ме подминаваш в FMI като пътен знак, а аз говоря на стената " Ей здравей ! "
:)
Просто исках да му го илюстрирам с пример.Но , и твоят начин с думи , става :) Всеки трябва да преоткрие своят начин на разбиране за нещата :)

Кога съм те подминал? :D Казвай здравей по-силно, не съм те видял :D

Въпроса беше, че интерфейса не може да има данни, а така както си го написал излиза, че данните са в интерфейса.
 
Jorko каза:
Значи правилно си мисля :D

Добре и друго искам да питам, защо да ползвам exception след като мога да ползвам echo или print, или да си създам масив с грешките и да го викам после?

Това е доста дълга тема :) За пример ще ти дам една функция, която връща потребител с администраторски права по ID:

Какво ще връща функцията, когато няма такъв потребител? Общо взето имаш 3 варианта:
1) Връщаш null/false/-1
2) Първото плюс записваш каква е грешката в масив от класа
3) Хвърляш смислен exception
4) ECHO/DIE/EXIT - това никога не се сещай за него за грешки. Никога, никога, никога, никога. Първо, че не можеш да разбереш има ли грешка (echo), показваш я на потребителя (лоша идея), чупиш си дизайна, правиш функцията неизползваема на друго място в кода, освен при дизайна на определено място. И нямаш никакъв начин дори и да има грешка да я "поправиш" по някакъв начин (например да пуснеш redirect, да изведеш хубаво съобщение, което няма да е хардкоднато в тая функция) и т.н.

Та примери:
1) и 2)
PHP:
public function getAdminUser($id)
{
[... database stuff ...]

if (<няма такова ID>)
{
$this->error = array('type' => 'noSuchUser');
return false;
}

if (<не е администратор>)
{
$this->error = array('type' => 'notAdmin');
return false;
}

return $user;
}

3)
PHP:
public function getAdminUser($id)
{
[... database stuff ...]

if (<няма такова ID>)
throw new NoSuchUserException();

if (<не е администратор>)
throw new UserNotAdminException();

return $user;
}

Как се проверява сега за грешката? И каква е грешката?
При 1) знаеш само, че има грешка. Значи в случая няма да ми свърши хубава работа. В следващия пример просто ще показвам текст с echo, но на практика ти ще си извикваш различна view за грешка или ще сетваш променливи към view-то. Просто си представи, че вместо echo има друга логика.

2)
PHP:
$userModel = ...;
$user = $userModel->getAdminUser($id);
if ($user === false)
{
if ($userModel->error['type'] == 'noSuchUser')
echo "Няма такъв потребител";
else if ($userModel->error['type'] == 'notAdmin')
echo "Не е администратор";
else
echo "Непозната грешка";
}

3)
PHP:
$userModel = ...;

try
{
$user = $userModel->getAdminUser($id);
}
catch (NoSuchUserException $e)
{
echo "Няма такъв потребител";
}
catch (UserNotAdminException $e)
{
echo "Не е администратор";
}
catch (Exception $e)
{
echo "Непозната грешка";
}

Кое изглежда по-прегледно? Освен това втория начин е мнооого по-податлив на грешки. Представи си, че си написал NoSuchUser в проверката, вместо noSuchUser. Еми няма да разбереш правилно каква е. Може да забравиш при някоя грешка да напишеш $this->error['type'] = нещо; и да проверяваш стара грешка. А може на някой метод просто да забравиш да провериш резултата дали е false/null и ако има грешка ще работиш с неверни данни.

Бях тръгнал да пиша още, ама всяко второ мнение в тая тема е мое и спирам да пиша тук, че вярно ще вземе да ме намрази някой :D
 
и да допалня нещо, когато ти "гръмне " db-to, хвърля exception, със заякви и така нататък, в python целия сайт спира, и Обикновенно трябва да позваш log файлове, да пишеш грешките, а с echo няма да го направиш. Потребителите не трябва да виждат твойте грешки, а единствено собствените си. Пример:
1.Когато потребител си среши user-а, pass и т.н
2. Когато имаш детайл view ако даденото id се повтаря(това е изцяло твоя грешка) или го няма, това абтоматично трябва да хвърли exception 404 или да не показваш страницата,защото ще му показваш глупости,и задалжително да бъде записамо в log файл
 
Само да ви подчертая че прекалено много използвате думите като view,model,controller не говорим за FRAMEWORK а ООП :D

ПП:Ако почна да ползва MVC структирата предпочитам аз да си напиша framework отколкото да боравя с вече готовите..

И тук избликва въпросът защо?!

Ами защото най важното докато пиша тоя framework ще натрупам най важното знанията :?:
 
Хмм.. FFDP

PHP:
Хората гледат, да не пишат по принцип излишен код, но ти освен че правиш функция, я добавяш и към клас.

Първо се нарича метод. Сега класът Security, може да се ползва като библиотека, в него ще набуташ и други методи свързани със сигурноста. Този метод hash() съм го дал за пример, но да ти кажа абсолютно нищо нередно не виждам в него. Представи си че задаваш един салт, който да е валиден за всички хешове ... след време ако искаш да промениш салта или както казаха няколко мнения преди мене: "да смениш хеширащата функция", ще трябва да обиколиш целия код за да заменяш. Не е ли по - лесно да имаш един метод и където ти потрябва да си го викаш, той да си слага салта, там различните видове хашове (който си избереш) и т.н.

За това става дума:
PHP:
class Security {

public function hash($value) {
     return md5($value);
 }

}


--------------------------------

Да се включа и аз за Exception темата.

Ползвай ги:

- Когато дадено нещо върне примерно true или false, примерно:

PHP:
if(!file_exist($file)) {

     throw new Exception('File does not exist');

}

include $file;

При ето такива ситуации ги ползвай.

Сега при какви да не ги ползваш.

- Примерно даден потребител си пише потребителското име и паролота, след това при несъответсвие, не е нужно да му хвърляш Exception, може да си ползваш обикновенните масиви или сессии за пренасяне на грешката до view - то.


Exception се показват единствено и само когато си във debug ситуация. Когато дадения проект се пусне публично, всичките Exception - и трябва да не се показват на потребителя, ами да се записват във някакъв Error Log и съответно на потребителя единствено може да се покаже, някаква смислена грешка, която да не реже сайта ами да е с тон със дизайна.

Така Exception - и те трябва да са максимално описващи дадения проблем, но и в същото време максимално кратки (като това вкл. на кой ред, каква грешка, пътя до там, почети всички възможни неща), за да може бързо да разбереш от къде идва проблема.

Може също да разгледаш за set_error_handler(); с нея просто хващаш всички грешки, който е възможно да ти генерира PHP при процес на разработка и ги пращаш към твоя функция, която във последствие може да ти генерира грешките от PHP във някой по хубав вид а и да ги записва във Error логове.

Друго забравих да кажа Exception не работи със Fatal Errors.
 
Давам един пример и ме интересува правилно ли извеждам данните като използвам PDO. И въпросното PDO освен за изваждане на резултат от базата за какво друго може да се използва?

PHP:
<?php
class DB {
	protected static $instance;
	protected function __construct() {}
	public static function getInstance() {
		if(empty(self::$instance)) {
			$db_info = array(
				"db_host" => "localhost",
				"db_port" => "3306",
				"db_user" => "root",
				"db_pass" => "",
				"db_name" => "database",
				"db_charset" => "UTF-8"
			);
			
			try {
				self::$instance = new PDO("mysql:host=".$db_info['db_host'].';port='.$db_info['db_port'].';dbname='.$db_info['db_name'], $db_info['db_user'], $db_info['db_pass']);
				self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);  
				self::$instance->query('SET NAMES utf8');
				self::$instance->query('SET CHARACTER SET utf8');
			}
			
			catch(PDOException $e) {  
				echo $e->getMessage();  
			}                          
		}
		return self::$instance;
	}
}
$db = DB::getInstance();

$query = $db->prepare("SELECT `username` FROM `users` WHERE `username`='gonka_7';");
$query->execute();
$result = $query->fetch(PDO::FETCH_OBJ);
echo $result->username;

echo "<hr />";

$sth = $db->query("SELECT `username` FROM `users`;");
$sth->setFetchMode(PDO::FETCH_OBJ);  
while($row = $sth->fetch()) {  
   echo $row->username."<br />";  
}

// INSERT
# $sth = $DBH->prepare("INSERT INTO `table` (first_name) VALUES ('Cathy');");
# $sth->execute();
?>
 
Ticketa каза:
Давам един пример и ме интересува правилно ли извеждам данните като използвам PDO. И въпросното PDO освен за изваждане на резултат от базата за какво друго може да се използва?

PHP:
<?php
class DB{
	
	protected static $instance = null; 
	protected $dbhost=""; //DB host
	protected $dbuser=""; //DB user
	protected $dbpass = ""; //DB pass
	protected $dbdb = ""; //Database
	protected  $conn = null;
	
	private function __construct(){
		
		try{
			$this->conn = new PDO('mysql:host='.$this->dbhost.';dbname='.$this->dbdb, $this->dbuser, $this->dbpass);
			$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
			$this->conn->query('SET NAMES utf8');
			$this->conn->query('SET CHARACTER SET utf8');
		}catch (PDOException $e)
		{
			echo 'Connection failed: ' . $e->getMessage();
			exit;
		}
		
	}
	
	/**
	 *  Функция за изпълнение на заявка
	 * 
	 *  @var string $sql
	 * @return array $qry
	 * 
	 */
	public function query($sql)
	{
		if(empty($sql))
		{
			Throw new \Exception('Query  cannot be empty!');
		}
		$qry = $this->conn->query($sql);
		return $qry;
	}
	
	/**
	 *  Singleton Design Pattern
	 * 
	 * @return object DB()
	 */
	public static function getInstance()
	{
		if(!self::$instance)
		{
			self::$instance = new DB();
		}
		return self::$instance;
	}
}

//Така се ползва
$db = DB::getInstance();
try{
$arr = $db->query('SELECT `credits` FROM `phpbb_users` WHERE `username`="Admin"');
foreach($arr as $k=>$v)
{
	echo $v['credits'];
}
}catch(Exception $e)
{
	echo $e->getMessage();
}
Ето ти правилно направен DB класа с PDO. Твоя код е грешен, не толкова грешен колкото неправилно направен.Ако искаш да ползваш функция от PDO в класа си направи нов метод и в него, чрез $this->conn си извикай функцията от PDO и след това си викай метода, където ти трябва
 
Идея : Този клас на пръв поглед ми хареса, обаче виждам нещо което доста ще осложни кода. Поне аз така мисля !
Това че при всяка заявка трябва да се хваща ексепшъна. Защо не го преместиш в query, и ако изгърми да връща празен масив ?
 

Back
Горе