Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Ola pessoal, esses dias comecei a estudar Orientado a objeto , depois disso fiz essa pagina onde ela faz consulta no banco de dados, com possível pesquisa. Essa pagina funciona perfeitamente , só vim aqui perguntar se estou fazendo corretamente, se não saiu do escopo Orientado a Objeto , sera que alguém pode me dar um opinião ?
Exemplo4.php
<?php
class Conectarbanco {
private $host = "localhost";
private $login = "root";
private $senha = "";
private $banco = "bd";
protected $BD;
protected function abrirBanco (){
$this -> BD = mysqli_connect($this -> host,$this -> login,$this -> senha,$this -> banco);
}
protected function fecharBanco(){
mysqli_close($this -> BD);
}
}
class Executar extends Conectarbanco{
protected $BD;
private $sql;
private $resultado;
private $linhas;
function __construct($pesquisa){
$this -> sql = "select * from produtos";
if($pesquisa != null){
$this -> sql .= " where nome_produto like '%$pesquisa%' ";
}
$this -> getProdutos();
}
private function getProdutos(){
$this -> abrirBanco();
$this -> resultado = mysqli_query($this -> BD,$this -> sql);
while ($this -> linhas = mysqli_fetch_assoc($this -> resultado)){
echo "<tr><td>".$this -> linhas['nome_produto']."</td>";
echo "<td>".$this -> linhas['valor']."</td></tr>";
}
$this -> fecharBanco();
}
}
?>
consultarprodutos.php
<?php
require'Exemplo4.php';
$pesquisa = NULL;
if(isset($_GET['pesquisa'])){
$pesquisa = $_GET['pesquisa'];
}
?>
<!DOCTYPE html>
<html>
<head>
<title> </title>
<meta charset='UTF-8'>
</head>
<body>
<form method='get' action='consultarprodutos.php'>
<input type='text' name='pesquisa' >
<input type='submit' value='Pesquisar'>
</form>
<table>
<tr>
<td>Nome</td>
<td>Preço</td>
</tr>
<?php $consulta = new Executar($pesquisa); ?>
</table>
</body>
</html>>
Show de bola cara.
Parabéns pelo progresso.
Não conheço a fundo como aplicar OO em php (da maneira certa), vou deixar alguém com mais bagagem comentar sobre isso..
Oq posso contribuir é sobre a segurança.
Sei que é apenas um exemplo.
Mas você deveria tratar a entrada de String já que está suscetível a sql injection.
$this -> sql .= " where nome_produto like '%$pesquisa%' ";
Você pode deixar seu codigo mais seguro utilizando isto:
http://php.net/manual/pt_BR/mysqli-stmt.bind-param.php
Vixe o que você me passou é novo pra mim vou ter que dar uma estudada ;X, eu achava que esse modo que eu fiz era seguro =(.
Bom dia,
da uma lida nisso aqui que vai te ajudar bastante quanto a tratar sql injection
Parabéns pela iniciativa, são poucos que colocam a "cara a tapa". Todavia, vamos as situações.
Essa é uma questão que envolve muitas variáveis e exige textos enormes, mas tentarei ser sucinto (devido a falta de tempo).
Uma questão muito importante é sobre o exemplo utilizado. Apesar de uma conexão com o banco de dados ser o exemplo mais comum (além de ser extremamente utilizado na prática), é um dos piores exemplo possível. Isso ao fato de que a orientação a objetos deve prever e abstrair certas diferenças. Em um SGBD, são tantas diferenças que a abstração se torna tão extensa que deixa de ser funcional.
Essa situação pode ser demonstrada através dos inúmeros padrões (design patterns) para o SGBD, tais como Data Maper, Table Data Gateway e Row Data Gateway, Data Access Object, etc). Por esse motivo, deve ser definido um pequeno escopo e não sair dele. No final, cada padrão terá seu ponto positivo e negativo.
Segundo ponto é uma questão sobre coesão e coerência (a mesma da língua portuguesa), veja bem:
Coesão é a conexão, ligação, harmonia entre os elementos de um texto. Percebemos tal definição quando lemos um texto e verificamos que as palavras, as frases e os parágrafos estão entrelaçados, um dando continuidade ao outro.Os elementos de coesão determinam a transição de ideias entre as frases e os parágrafos.
A coerência textual é a relação lógica entre as ideias, pois essas devem se complementar, é o resultado da não contradição entre as partes do texto.
A relação entre objetos deve possuir responsabilidades e estas sair dos seus limites. Isso também pode ser visto no S do S.O.L.I.D.
Você poderá ver muito nesta thread:
http://forum.imasters.com.br/topic/510435-solid-principio-da-responsabilidade-unica/
Outra parte da coesão, é manter a parte textual dentro do mesmo escopo. Ou seja, se você está programando em inglês (idioma da linguagem de programação), mantenha as "coisas" em inglês.
Próximo ponto, é sobre o tipo de relacionamento (vertical x horizontal). O relacionamento vertical é definido através de generalização e especialização (herança). O relacionamento horizontal, por outro lado, possui diversos tipos, tais como associação (simples, agregação e composição), interfaces e traits.
Além disso, existe a exemplificação de é um e de usa um, o que pode ser visto no link abaixo:
http://forum.imasters.com.br/topic/545070-como-implementar-solid-sem-violar-seus-principios/
No seu caso, a classe Executar não é um banco de dados (ou uma conexão), ela utiliza um banco de dados (ou uma conexão) para realizar as suas ações.
Nesse caso, é importante entender sobre injeção de dependência. Os links acima possuem conteúdos explicando também esse assunto.
Sobre o questionamento do @gabrieldarezzo é sobre preparede staments, aonde você cria um statement (uma consulta) e, após, adiciona suas variáveis na executação.
sobre o relacionamento (vertical x horizontal) eu li todos os links que você mandou, ainda assim pesquisei mais sobre mas não entendi muito bem, apenas entendi que o relacionamento vertical causa muitos problemas futuros e digamos que é uma forma errada de se trabalhar, mas não entendi como assim relacionamento vertical x horizontal ?
Relacionamento vertical é aquele que obrigatoriamente implica no relacionamento de uma camada superior com uma inferior. Esse relacionamento é possível somente através da herança (generalização <-> especializada), seja ela simples ou múltipla.
Relacionamento horizontal é aquele que você pode relacionar elementos de uma mesma camada que não implicam na existência de uma outra camada, tal qual associação, interface e traits.
As traits, são um caso a parte, pois tentam prover a herança múltipla. Mas na realidade é o "copy 'n paste" de código. E tal qual uma interface, pode existir somente em uma camada.
[...]apenas entendi que o relacionamento vertical causa muitos problemas futuros e digamos que é uma forma errada de se trabalhar[...]
Aqui entra um parênteses, pois, não é nem um pouco errado de se trabalhar, só normalmente é mal empregado. O entendimento comum, e errado, de herança, é a reutilização de código. Quando uma classe necessitar de outra, acaba-se estendendo-a e é ai que está o erro.
Normalmente essa situação é resolvida com os questionamentos: "A classe X é uma ou usa uma classe Y?
Outro detalhe é a representação gráfica dos relacionamentos através de um diagrama de classes, como no diagrama abaixo:
/applications/core/interface/imageproxy/imageproxy.php?img=http://www.tutorialspoint.com/uml/images/uml_class_diagram.jpg&key=0a6b733971138396a2b750163032b4c25154179e50da8eaf616dbb7835bfedf3" alt="uml_class_diagram.jpg" />
SpecialOrder e NormalOrder são sub-classes (especializações) de Order, isso é um relacionamento vertical, já uma Order (seja ela Normal ou Special) está relacionada a um Costumer (cliente) e um Costumer pode ter N Order. Esse é um relacionamento horizontal.
eu assisti o seguinte vídeo
acho que entendi um pouco sobre relacionamento horizontal e a partir dele fiz alguns ajustes , lembrando que ainda não mexi no quesito de segurança do Banco
<?php
require'class.php';
?><html>
<head>
<title> </title>
<meta charset='UTF-8'>
</head>
<body>
<form method='get' action='consultarprodutos.php'>
<input type='text' name='pesquisa' >
<input type='submit' value='Pesquisar'>
</form>
<table>
<tr>
<td>Nome</td>
<td>Preço</td>
</tr>
<?php
$consulta = new Produtos();
if(isset($_GET['pesquisa'])){
$consulta -> selectProdutos($_GET['pesquisa']); $consulta -> selectProdutos(NULL);
}
?>
</table>
</body>
</html>
<?php private $host = "localhost";
private $login = "root";
private $pass = "";
private $database = "bd";
public $DB;
public function openDataBase (){
$this -> BD = mysqli_connect($this -> host,$this -> login,$this -> pass,$this -> database);
return $this -> BD;
}
public function closeDataBase(){
mysqli_close($this -> BD);
return $this -> BD;
}
}
class Produtos {
private $sql;
private $result;
private $lines;
private $database;
public function selectProdutos($pesquisa){
$this -> sql = "select * from produtos";
if($pesquisa != null){
$this -> sql .= " where nome_produto like '%$pesquisa%' ";
}
$this -> getProdutos();
}
private function getProdutos(){
$database = new Connectdatabase();
$database -> openDataBase();
$this -> result = mysqli_query($database -> BD,$this -> sql);
while ($this -> lines = mysqli_fetch_assoc($this -> result)){
echo "<tr><td>".$this -> lines['nome_produto']."</td>";
echo "<td>".$this -> lines['valor']."</td></tr>";
}
$database -> closeDataBase();
}
}
?>O acoplamento do seu código continua muito alto. No momento, você está violando o princípio de responsabilidade única (S.R.P).
Imagine que, em dado momento, as configurações de acesso a banco sejam alterados. Você necessitará alterar sua classe para que sua conexão volte a funcionar.
Mas esse não é a única questão. E se, em dado momento, você precisar consultar produtos de dois SGBDs distintos. Como você procederá? Duplicará a classe Produtos para ProdutosSGBDX?
Essas duas situações são facilmente resolvidas através da injeção de dependência.
Existem outras questões que também podem ser abordadas, como o fato da entity (entidade Produtos) conhecer sobre sua persistência. Isso varia conforme o modelo de persistência adotado e, de fato, o ActiveRecord, que aborda essa metodologia, fere o S.R.P (know to much).
Uma linha no PHP: The Right Way pode lhe ajudar.
Olá, como vai!
Primeiramente evite que classes da sua aplicação fique abrindo conexões com o banco de dados, como é possível ver na classe Produtos > "new Connectadatabase()", se um dia você mudar o modo de gerenciamento de conexão, vai ter que abrir todas as suas classes para fazer a mudança by hand!
Quando vi o modo como você escreve seu código, eu fiz login no forum imediatamente, recebi um grande tapa na cara ao ver isso ai que você escreveu.
Desculpe pelo modo como me expresso, se pareço duro, mas não existe outra forma de fazer você se tornar um profissional de alto nível.
>
$this -> BD
Você já errou em escrever BD quando in fact nomeou a propriedade como DB, veja como você escreve o operador -> com espaços, em seguida é possível ver vários saltos de linhas desnecessários.
Para corrigir esses vícios, estude sobre PSR-2, isso mesmo, entra no Google e escreve PHP PSR-2, vai ter tudo que você precisa saber sobre como identar e escrever corretamente seus códigos.
CLASSE GERENCIADORA DE DADOS DE CONEXÃO
>
private $host = "localhost";
private $login = "root";
private $pass = "789456123g";
private $database = "bd";
public $DB; (X)
Por favor, não utilize essas propriedades da classe como se fossem constantes, definindo-as previamente e tornando-as imutáveis.
Acima você criou uma classe de conexão que vai servir apenas para um banco de dados e será impossível se conectar a qualquer outro que precisar, o que fará quando tiver que conectar a mais de um banco usando uma mesma classe gerenciadora de dados da conexão?
A classe gerenciadora de dados da conexão não deve saber com o que está se conectando, se mysql ou outro e não pode chamar diretamente funções como mysqli_*, instanciar PDO e outros.
Ela trata apenas dos dados e como tal deve se passada para os verdadeiros conectores que farão a conexão com seus gerenciadores instalados no sistema operacional usando esses dados
Uma propriedade chamada DB em uma classe de dados de conexão não existe!
vlw pessoal vou dar uma estudada nas dicas que você me mandarão em breve posto o resultado, acho que agora estou começando a entender a coisa.
Não entendi o porque da classe "Executar"...ainda mais tendo como construtor um select....parece ficar muito preso e específico. Eu faria a classe Executar com os metódos do crud usando pdo, já q o foco é OOP
aquele foi meu primeiro código to aprendendo '-' , daqui a pouco posto outro, agora acho que vai.
aquele foi meu primeiro código to aprendendo '-' , daqui a pouco posto outro, agora acho que vai.
Ah saquei man, malz.. Mas muito joia (y) recomendo um livro legal :
Boa noite, como estamos falando de OOP eu não faria um relacionamento de herança ali na classe Executar. A herança na programação orientada a objetos é usada geralmente quando é preciso de uma herança por exemplo: Animal (Superclasse), Cachorro (Classe-filha), Gato (Classe-filha), perceba que para esses tipos de classe eu preciso de uma herança, pois existem atributos e métodos na superclasse que também são necessários para as classes-filhas. Porque esse é o ponto forte e fraco da herança, quando você herda, você traz todo o código, as vezes para usar apenas um atributo ou um método, o que dá para ver que não é vantagem.
Nesse seu caso você deve dar uma olhada em UML, nas relações de associação, composição e agregação, segue link:
https://www.todoespacoonline.com/w/2014/08/associacao-agregacao-e-composicao/
Na prática faria uma associação, por exemplo, código em java só para entender a relação de que um carro tem um motor.
public class Carro{
private String $marca;
private String $modelo;
public Motor $m;
//métodos e demais atributos
}
public Motor{
// atributos de motor
}
Com isso eu consigo acessar tudo da classe Motor sem precisar herdar toda a classe, utilizando assim somente o que eu necessito e não linhas e linhas de código desnecessárias.
Abraços,
Matheus
config.ini
driver = mysql
host = localhost
;port = 3306
dbname = bd
username = root
password = 123
class.php
<?php
class ConnectDataBase
{
function connect($file = 'config.ini')
{
$file = parse_ini_file($file, TRUE);
$this -> link = mysqli_connect($file['host'],$file['username'],$file['password'],$file['dbname']);
return $this -> link;
}
public function __destruct()
{
mysqli_close($this -> link);
}
}
class Query extends ConnectDataBase
{
private $result;
private $lines;
function __Construct($sql)
{
$link = parent::connect();
$this -> result = mysqli_query($link,$sql);
}
public function getResult()
{
$i=0;
while($this -> lines[$i] = mysqli_fetch_assoc($this -> result)){
$i++;
}
return $this -> lines;
}
}
?>
consultarprodutos.php
<?php
require'class.php';
?>
<!DOCTYPE html>
<html>
<head>
<title> </title>
<meta charset='UTF-8'>
</head>
<body>
<form method='get' action='consultarprodutos.php'>
<input type='text' name='pesquisa' >
<input type='submit' value='Pesquisar'>
</form>
<?php
$consulta = new Query('select * from produtos');
$rows = $consulta -> getResult();
?>
<table>
<tr>
<td>Nome</td>
<td>Preço</td>
</tr>
<?php
$i = 0;
while ($rows[$i])
{
echo "<tr><td>".$rows[$i]['nome_produto']."</td>";
echo "<td>".$rows[$i]['valor']."</td></tr>";
$i++;
}
?>
</table>
</body>
</html>
Ae pessoal esse é o resultado de meu estudo desses dias, queria saber a opniao de você, para saber se estou quase lá, ou se alguém tiver alguma dica.
>
Ah saquei man, malz.. Mas muito joia (y) recomendo um livro legal :
http://novatec.com.br/livros/php-orientacao-objetos-3ed/
Estou gostando muito do livro mano, serio ta ajudando muito, to na pag 120.
>
$file = parse_ini_file($file, TRUE); (x)
$this -> link = mysqli_connect (x)
Não precisa nada disso ai amigo
Você ainda está utilizando mysqli dentro de uma classe que era somente para dados da conexão.
Deixe o MySql separado, por exemplo, crie um estrutura de pasta da seguinte forma
• db
:
• db / driver / mysql
Dentro da pasta "db" terá uma interface de dados de conexão
AbstractConnector.php
<?php
abstract class AbstractConnector
{
/**
* Ou $host, como desejar
* @var string
/
protected $server = "localhost";
/**
* @var string
* */
protected $user = "";
/**
* @var string
* */
protected $password = "";
/**
* @var string
* */
protected $port = "";
/**
* @var string
* */
protected $database = "";
public function __construct($user, $password, $port, $database, $server = "localhost")
{
$this->user = $user;
$this->password = $password;
$this->port = $port;
$this->database = $database;
$this->server = $server;
}
/**
* Deixamos para o conector concreto implementar
* @return boolean
* */
abstract public function connect();
/**
* Ou getHost(), como desejar
* */
public function getServer()
{
return $this->server;
}
public function getDb()
{
return $this->database;
}
public function getPassword()
{
return $this->password;
}
public function getUser()
{
return $this->user;
}
}MySqlConnector.php
class MySqlConnect extends AbstractConnector
{
/**
* Agora aqui você poderá usar as funções mysqli
* AbstractConnector::connect();
* */
public function connect()
{
return mysqli_connect(
$this->server,
$this->user,
$this->password,
$this->database
);
}
}
Note que não estou usando PDO e nem outros paradigmas para que você entenda facilmente a lógica.
Agora você vai fazer com que sua aplicação não saiba que está se conectando ao MySql ou a qualquer outro, assim no futuro poderá mudar alterando apenas uma linha, vou implementar da forma mais simples que existe, só para que entenda.
Dentro da pasta "db" crie uma classe chamada DatabaseConnector
DatabaseConnector.php
<?php
class DatabaseConnector
{
protected $connector;
public function connect($user, $password, $port, $database, $server = "localhost")
{
$this->connector = new MySqlConnect($user, $password, $port, $database, $server);
return $this->connector->connect();
}
public function getConnector()
{
return $this->connector;
}
}
Agora eu posso conectar a qualquer banco de dados sem que minha aplicação saiba qual é
<?php
new DatabaseConnector(/*[...]*/);
É claro que existem formas muito mais avançadas de fazer, mas isso é apenas um simples exemplo para que você entenda um pouco.
Dessa vez você separou entre as classes ConnectDataBase e Query. A classe Query se tornou uma especialização da classe ConnectDataBase.
ConnectDataBase é a conexão com base de dados e Query é a consulta com a base de dados. Entretanto, uma consulta (Query) não é uma conexão com a base de dados (ConnectDataBase). A consulta utiliza uma conexão.
Isso tem um efeito colateral muito alto, a cada consulta que você realizar, estará criando uma nova conexão, sendo que uma, no seu caso, é mais que o necessário.
O parse de um config.ini, apesar de ser bem interessante ser utilizado, está aplicado no lugar errado. Sua classe está tendo mais de uma responsabilidade (se lembra da S.R.P?).
Ou seja, sua classe tem mais de uma razão para ser alterada, vejam as razões:
- Realiza o parse de files;
- Gerencia a configuração de conexão;
Ou seja:
- Se mudar o local da configuração ou tipo (json, xml, etc..);
- Se entra uma nova configuração (port por exemplo);
Lembrando que MySQLi possui uso tanto procedural como orientado à objetos. E como no seu caso é orientação à objetos, sugiro utilizar a biblioteca como tal.
Eu recomendo a leitura dos seguintes links:
http://forum.imasters.com.br/topic/510435-solid-principio-da-responsabilidade-unica/
http://forum.imasters.com.br/topic/464790-vo-dto-model-dao/
Além do livro PHP Objecs, Patterns, Pratice (existe em português).
Também é importante conhecer o que o "mercado" oferece de padrões existentes. Para entender quais caminhos foram traçados e o porque de suas escolhas.
TableDataGateway + RowDataGateway
DataMapper (esse você encontra no livro acima mencionado).
Doctrine (Biblioteca que contempla ORM e DBAL, além de diversas funcionalidades)
Como eu mencionei anteriormente, o exemplo de banco de dados não é muito aconselhável para aprendizado, pois ele envolve tantas variáveis, além de N tecnologias empregadas, que sua abstração existe dois pontos: Ou não contempla todas as possibilidades ou se torna tão granularizada que se torna de difícil uso e manutenibilidade.
Dessa forma entra outra situação, o que é o melhor para o seu uso e para o seu projeto, sem violar os design principles.
Cuidado com a herança, ainda está errado(menos funcional).
Abraços,
Matheus
caramba achei que tinha acertado agora, vou estudar mais , vlw pelas dicas.
Ae galera dei uma estudada esses dias e li todos os comentários e cheguei ao seguinte resultado, quero saber se estou tendo progressos, obrigado a todos que estão me ajudando.
class2.php
<?php
class DataBase
{
protected $dns;
protected $user;
protected $password;
function __construct($file = 'config.ini')
{
$file = parse_ini_file($file, TRUE);
$this -> dns = $file['driver'].":host=".$file['host'].";dbname=".$file['dbname'].";port=".$file['port'];
$this -> user = $file['user'];
$this -> password = $file['password'];
}
} static $link = NULL;
function getLink()
{
if(self::$link)
{
return self::$link;
}
self::$link = new PDO($this->dns,$this->user,$this->password) ;
return self::$link;
}
} function executeQuery($query,$param = null)
{
if($param)
{
}
$result = Connection::$link->query($query);
return $result;
}
}
consultaprodutos.php
<?php
require'class2.php';
?>
<!DOCTYPE html>
<html>
<head>
<title> </title>
<meta charset='UTF-8'>
</head>
<body>
<form method='get' action='consultarprodutos.php'>
<input type='text' name='pesquisa' >
<input type='submit' value='Pesquisar'>
</form>
<?php
$consulta = new Connection();
$consulta -> getLink();
$resultado = new QueryDataBase;
$result = $resultado -> executeQuery("select * from produtos");
?>
<table>
<tr>
<td>Nome</td>
<td>Preço</td>
</tr>
<?php
while($row = $result->fetch(PDO::FETCH_OBJ)){
echo "<tr><td>".$row->nome_produto."</td>";
echo "<td>".$row->valor."</td></tr>";
}
?>
</table>
</body>
</html>
Show de bola cara.
Parabéns pelo progresso.
Não conheço a fundo como aplicar OO em php (da maneira certa), vou deixar alguém com mais bagagem comentar sobre isso..
Oq posso contribuir é sobre a segurança.
Sei que é apenas um exemplo.
Mas você deveria tratar a entrada de String já que está suscetível a sql injection.
$this -> sql .= " where nome_produto like '%$pesquisa%' ";
Você pode deixar seu codigo mais seguro utilizando isto:
http://php.net/manual/pt_BR/mysqli-stmt.bind-param.php