blob: 1a339ec14c0ed8f2f6b32f83ea0a198e48205461 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= Criando uma Aplicação Orientada pelo Banco de Dados com o PHP
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: Criando uma Aplicação Orientada pelo Banco de Dados com o PHP - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, Criando uma Aplicação Orientada pelo Banco de Dados com o PHP
= Lição 4: Otimizando o Código com Classes e Objetos
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: Lição 4: Otimizando o Código com Classes e Objetos - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, Lição 4: Otimizando o Código com Classes e Objetos
Nesta lição, você otimizará o código para facilitar sua manutenção no futuro. Isso afeta os arquivos `createNewWisher.php` e `wishlist.php` . Além disso, um novo arquivo chamado `db.php` é criado.
O código do sua aplicação contém vários blocos de código semelhantes com consultas ao banco de dados. Para facilitar a leitura e a manutenção do código no futuro, você pode extrair esses blocos, implementá-los como funções de uma classe separada chamada `WishDB` e colocar `WishDB` em `db.php` . Depois disso, você pode incluir o arquivo `db.php` em qualquer arquivo PHP e usar qualquer <<includedFunctions,função de WishDB>> sem duplicação de código. Essa abordagem garante que quaisquer alterações em consultas ou funções serão feitas em um único local e você não terá de fazer parsing do código inteiro da aplicação.
Ao usar uma função de WishDB, você não altera o valor de quaisquer variáveis de WishDB. Em vez disso, use a classe WishDB como um plano gráfico para criar um objeto de WishDB, e altere os valores das variáveis nesse objeto. Quando você finaliza o trabalho com esse objeto, ele é destruído. Como os valores da classe WishDB nunca são alterados, você pode reutilizar a classe por um número ilimitado de vezes. Em alguns casos, talvez você queira ter várias instâncias de uma classe ao mesmo tempo, e em outros casos, talvez você prefira uma classe "única", onde você possui apenas uma instância de cada vez. O WishDB neste tutorial é uma classe única.
Observe que o termo para criar um objeto de uma classe é "instanciar" essa classe, e que outra palavra para um objeto é uma "instância" de uma classe. O termo geral para programar com classes e objetos é "programação orientada por objeto" ou OOP. O PHP 5 usa um modelo OOP sofisticado. Consulte link:http://us3.php.net/zend-engine-2.php[+php.net+] para obter mais informações.
Neste tutorial, a funcionalidade de chamada do banco de dados é movida de arquivos PHP individuais para classes WishDB. Usuários do MySQL também podem substituir a chamada `mysqli` de estilo de procedimento por chamadas orientadas por objetos. Isso é para manter com o novo projeto orientado por objetos da aplicação
O documento atual é uma parte do tutorial Criando uma Aplicação CRUD no NetBeans IDE para PHP.
[[previousLessonSourceCode]]
== Código-fonte da Aplicação da Lição Anterior
Usuários MySQL: clique link:https://netbeans.org/files/documents/4/1929/lesson3.zip[+aqui+] para fazer o download do código-fonte que reflete o estado do projeto depois que a lição anterior estiver concluída.
Usuários do Banco de Dados Oracle: clique link:https://netbeans.org/projects/www/downloads/download/php%252Foracle-lesson3.zip[+aqui+] para fazer o download do código-fonte que reflete o estado do projeto depois que a lição anterior estiver concluída.
[[createDbPhpFile]]
== Criando o Arquivo db.php
Crie uma nova subpasta na pasta Códigos-fonte. Nomeie a pasta Inclusão. Crie uma nova pasta nomeada db.php e coloque em Inclusão. Depois disso, é possível adicionar mais arquivos para essa pasta que será incluída em outros arquivos PHP.
*Para criar o db.php em uma nova pasta:*
1. Clique com o botão direito do mouse no nó Código-fonte e selecione Novo > Pasta no menu de contexto. A caixa de diálogo Nova Pasta é aberta.
2. No campo Nome da Pasta, digite Inclusão. Em seguida, clique em Finalizar.
3. Clique com o botão direito do mouse no nó Inclusão e selecione Novo > Arquivo PHP no menu de contexto. A caixa de diálogo Novo Arquivo PHP é aberta.
4. No campo Nome do Arquivo, digite db. Em seguida, clique em Finalizar.
[[wishDBClass]]
== Criando a Classe WishDB
Para criar a classe WishDB, você precisa inicializar as variáveis da classe e implementar um construtor da classe. Usuários MySQL, observem a classe WishDB _extends_ `mysqli` . Isso significa que o WishDB _herda_ a função e outras características da classe mysqli PHP. A importância disso é mostrada ao adicionar as funções `mysqli` à classe.
Abra o arquivo db.php e crie a classe WishDB. Na classe, declare variáveis de configuração de banco de dados para armazenar o nome e a senha do proprietário do banco de dados (usuário), o nome e o host do banco de dados. Todas essas declarações de variável são "privadas", o que significa que os valores iniciais nas declarações não podem ser acessados de fora da classe WishDB (Consulte link:http://us3.php.net/manual/en/language.oop5.visibility.php[+php.net+]). Declare também a variável _ static_ `$instance` privada, que armazena a instância do WishDB. A palavra-chave “estática” significa que a função na classe pode acessar a variável mesmo quando não há instância da classe.
*Para o Banco de Dados MySQL:*
[source,php]
----
class WishDB extends mysqli {
// single instance of self shared among all instances
private static $instance = null;
// db connection config vars
private $user = "phpuser";
private $pass = "phpuserpw";
private $dbName = "wishlist";
private $dbHost = "localhost";
}
----
*Para o Banco de Dados Oracle:*
[source,php]
----
class WishDB {
// single instance of self shared among all instances
private static $instance = null;
// db connection config vars
private $user = "phpuser";
private $pass = "phpuserpw";
private $dbName = "wishlist";
private $dbHost = "localhost/XE";
private $con = null;
}
----
[[instantiate-wishdb]]
== Instanciando a classe WishDB
Para outros arquivos PHP usarem funções na classe WishDB, esses arquivos PHP precisam chamar uma função que crie um objeto ("instantiates") da classe WishDB. WishDB é designado como uma link:http://www.phpclasses.org/browse/package/1151.html[+classe única+], o que significa que somente uma instância da classe existe de cada vez. Portanto, é útil evitar qualquer instanciação externa de WishDB, o que poderia criar instâncias duplas.
Dentro da classe WishDB, digite ou cole o seguinte código:
[source,php]
----
// This method must be static, and must return an instance of the object if the object
// does not already exist.
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
// The clone and wakeup methods prevents external instantiation of copies of the Singleton class,
// thus eliminating the possibility of duplicate objects.
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Deserializing is not allowed.', E_USER_ERROR);
}
----
A função `getInstance` é "pública" e "estática." "Pública" significa que ela pode ser acessada publicamente de fora da classe. "Estática" significa que a função está disponível mesmo quando a classe não tiver sido instanciada. Como a função `getInstance` é chamada para instanciar a classe, ela deve ser estática. Observe que essa função acessa a variável `$instance` estática e ajusta os valores como a instância da classe.
Os dois-pontos duplos (::), chamados de Operador de Resolução de Escopo, e a palavra-chave `self` são usados para acessar funções estáticas. `Self` é usado na definição da classe para se referir à classe em si. Quando os dois-pontos duplos forem usados fora da definição da classe, o nome da classe será usado em vez de `self` . Consulte link:http://us3.php.net/manual/en/language.oop5.paamayim-nekudotayim.php[+php.net no Operador de Resolução de Escopo+].
[[wishdb-constructor]]
== Adicionando um Construtor à Classe WishDB
Uma classe pode conter um método especial conhecido como 'construtor', que é processado automaticamente sempre que uma instância dessa classe é criada. Neste tutorial, você adiciona um construtor ao WishDB que se conecta ao banco de dados sempre que WishDB é instanciado.
Adicione o código seguinte ao WishDB:
*Para o banco de dados MySQL:*
[source,php]
----
// private constructor
private function __construct() {
parent::__construct($this->dbHost, $this->user, $this->pass, $this->dbName);
if (mysqli_connect_error()) {
exit('Connect Error (' . mysqli_connect_errno() . ') '. mysqli_connect_error());
}
parent::set_charset('utf-8');
}
----
*Para o banco de dados Oracle:*
[source,php]
----
// private constructor
private function __construct() {
$this->con = oci_connect($this->user, $this->pass, $this->dbHost);
if (!$this->con) {
$m = oci_error();
echo $m['message'], "\n";
exit;
}
}
----
Observe o uso da pseudovariável `$this` em vez das variáveis `$con` , `$dbHost` , `$user` ou `$pass` . A pseudovariável `$this` é usada quando um método é chamado de dentro do contexto de um objeto. Ela se refere ao valor de uma variável nesse objeto.
[[includedFunctions]]
== Funções da Classe WishDB
Nesta lição, você implementará as seguintes funções da classe WishDB:
* <<getIDByName,get_wisher_id_by_name>> para recuperar o id de um wisher com base em seu nome
* <<getWishesByID,get_wishes_by_wisher_id>> para recuperar uma lista de desejos do wisher com um id específico
* <<createWisher,create_wisher>> para adicionar um novo registro de wisher aos wishers da tabela
[[getIDByName]]
=== Função get_wisher_id_by_name
A função requer o nome de um wisher como parâmetro de entrada e retorna o wisher id.
Digite ou cole a seguinte função na classe WishDB, depois da função WishDB:
*Para o banco de dados MySQL:*
[source,php]
----
public function get_wisher_id_by_name($name) {
$name = $this->real_escape_string($name);
$wisher = $this->query("SELECT id FROM wishers WHERE name = '" . $name . "'");
if ($wisher->num_rows > 0){
$row = $wisher->fetch_row();
return $row[0];
} else {
return null;
}
}
----
*Para o banco de dados Oracle:*
[source,php]
----
public function get_wisher_id_by_name($name) {
$query = "SELECT id FROM wishers WHERE name = :user_bv";
$stid = oci_parse($this->con, $query);
oci_bind_by_name($stid, ':user_bv', $name);
oci_execute($stid);
//Because user is a unique value I only expect one row
$row = oci_fetch_array($stid, OCI_ASSOC);
if ($row) {
return $row["ID"];
} else {
return null;
}
}
----
O bloco de código executa a consulta `SELECT ID FROM wishers WHERE name = [variável para o nome do wisher]` . O resultado da consulta é um array de IDs dos registros que satisfazem a consulta. Se o array não estiver vazio, isso significa automaticamente que ele contém um elemento, porque o nome do campo é especificado como UNIQUE durante a criação da tabela. Nesse caso, a função retorna o primeiro elemento do array `$result` (o elemento com zero). Se o array estiver vazio, a função retornará nula.
*Observação sobre Segurança:* Para o banco de dados MySQL, a string `$name` tem escape para evitar os ataques de injeção SQL. Consulte link:http://en.wikipedia.org/wiki/SQL_injection[+Wikipedia sobre injeções SQL+] e a documentação mysql_real_escape_string. Embora no contexto deste tutorial você não esteja correndo o risco de injeções SQL prejudiciais, recomendamos escapar as strings nas consultas MySQL que estariam correndo risco de tal ataque. O banco de dados Oracle evita esse problema usando variáveis de ligação.
[[getWishesByID]]
=== Função get_wishes_by_wisher_id
A função exige o id de um wisher como o parâmetro de entrada e retorna os desejos registrados para o wisher.
Indique o seguinte bloco de código:
*Para o banco de dados MySQL:*
[source,php]
----
public function get_wishes_by_wisher_id($wisherID) {
return $this->query("SELECT id, description, due_date FROM wishes WHERE wisher_id=" . $wisherID);
}
----
*Para o banco de dados Oracle:*
[source,php]
----
public function get_wishes_by_wisher_id($wisherID) {
$query = "SELECT id, description, due_date FROM wishes WHERE wisher_id = :id_bv";
$stid = oci_parse($this->con, $query);
oci_bind_by_name($stid, ":id_bv", $wisherID);
oci_execute($stid);
return $stid;
}
----
O bloco de código executa a consulta `"SELECT id, description, due_date FROM wishes WHERE wisherID=" . $wisherID` e retorna um conjunto de resultados que é um array de registros que atende à consulta. (O banco de dados Oracle usa variáveis de ligação para o desempenho do banco de dados e motivos de segurança). A seleção é realizada pelo wisherID, que é a chave estrangeira dos `desejos` da tabela.
*Observação:* o valor `id` não é necessário até a Lição 7.
[[createWisher]]
=== Função create_wisher
A função cria um novo registro na tabela de wishers. A função requer o nome e a senha de um novo wisher como os parâmetros de entrada e não retorna dados.
Indique o seguinte bloco de código:
*Para o banco de dados MySQL:*
[source,php]
----
public function create_wisher ($name, $password) {
$name = $this->real_escape_string($name);
$password = $this->real_escape_string($password);
return $this->query("INSERT INTO wishers (name, password) VALUES ('" . $name . "', '" . $password . "')");
}
----
*Para o banco de dados Oracle:*
[source,php]
----
public function create_wisher($name, $password) {
$query = "INSERT INTO wishers (name, password) VALUES (:user_bv, :pwd_bv)";
$stid = oci_parse($this->con, $query);
oci_bind_by_name($stid, ':user_bv', $name);
oci_bind_by_name($stid, ':pwd_bv', $password);
oci_execute($stid);
return $stid;
}
----
O bloco de código executa a consulta `"INSERT wishers (Name, Password) VALUES ([variáveis representando o nome e a senha do novo wisher]).` A consulta adiciona um novo registro à tabela "wishers" com os campos "nome" e "senha" preenchidos com os valores de `$name` e `$password` respectivamente.
[[refactoring]]
== Refatorando o Código da Sua Aplicação
Agora que tem uma classe separada para trabalhar com o banco de dados, você pode substituir blocos duplicados por chamadas para as funções relevantes desta classe. Isso ajudará a evitar erros ortográficos e inconsistência no futuro. A otimização de código que não afeta a funcionalidade é chamada de refatoração.
[[refactoringWishlistFile]]
=== Refatorando o Arquivo wishlist.php
Comece com o arquivo wishlist.php porque ele é pequeno e as melhorias serão mais ilustrativas.
1. Na parte superior do bloco <?php ?> , insira a linha seguinte para permitir o uso do arquivo `db.php` :
[source,java]
----
require_once("Includes/db.php");
----
[start=2]
. Substitua o código que estabelece conexão com o banco de dados e que obtém o wisher ID por uma chamada para a função `get_wisher_id_by_name` .
Para o *banco de dados MySQL*, o código a ser substituído é:
[source,php]
----
// to remove
$con = mysqli_connect("localhost", "phpuser", "phpuserpw");
if (!$con) {
exit('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
//set the default client character set
mysqli_set_charset($con, 'utf-8');
mysqli_select_db($con, "wishlist");
$user = mysqli_real_escape_string($con, $_GET['user']);
$wisher = mysqli_query($con, "SELECT id FROM wishers WHERE name='" . $user . "'");
if (mysqli_num_rows($wisher) < 1) {
exit("The person " . $_GET['user'] . " is not found. Please check the spelling and try again");
}
$row = mysqli_fetch_row($wisher);
$wisherID = $row[0];
mysqli_free_result($wisher);
// to replace
$wisherID = WishDB::getInstance()->get_wisher_id_by_name($_GET["user"]);
if (!$wisherID) {
exit("The person " .$_GET["user"]. " is not found. Please check the spelling and try again" );
}
----
Para o *banco de dados Oracle*, o código a ser substituído é:
[source,php]
----
// to remove
$con = oci_connect("phpuser", "phpuserpw", "localhost/XE");
if (!$con) {
$m = oci_error();
echo $m['message'], "\n";
exit;
}
$query = "SELECT ID FROM wishers WHERE name = :user_bv";
$stid = oci_parse($con, $query);
$user = $_GET['user'];
oci_bind_by_name($stid, ':user_bv', $user);
oci_execute($stid);
//Because user is a unique value I only expect one row
$row = oci_fetch_array($stid, OCI_ASSOC);
if (!$row) {
echo("The person " . $user . " is not found. Please check the spelling and try again" );
exit;
}
$wisherID = $row['ID'];
// to replace
$wisherID = WishDB::getInstance()->get_wisher_id_by_name($_GET["user"]);
if (!$wisherID) {
exit("The person " .$_GET["user"]. " is not found. Please check the spelling and try again" );
}
----
O novo código chama primeiro a função `getInstance` no WishDB. O `getInstance` retorna uma instância de WishDB, e o código chama a função `get_wisher_id_by_name` dentro dessa instância. Se a lista de desejos solicitada não for encontrada no banco de dados, o código terminará o processo, e exibirá uma mensagem de erro.
Nenhum código é necessário para abrir uma conexão ao banco de dados. A conexão é aberta pelo construtor da classe WishDB. Se o nome e/ou a senha for alterado, você precisará atualizar somente as variáveis relevantes da classe WishDB.
[start=3]
. Substitua o código que recebe desejos de um wisher identificado pelo ID com um código que chama a função `get_wishes_by_wisher_id` .
Para o *banco de dados MySQL*, o código a ser substituído é:
[source,php]
----
// to remove
$result = mysqli_query($con, "SELECT description, due_date FROM wishes WHERE wisher_id=" . $wisherID);
// to replace
$result = WishDB::getInstance()->get_wishes_by_wisher_id($wisherID);
----
Para o *banco de dados Oracle*, o código a ser substituído é:
[source,php]
----
// to remove
$query = "SELECT description, due_date FROM wishes WHERE wisher_id = :id_bv";
$stid = oci_parse($con, $query);
oci_bind_by_name($stid, ":id_bv", $wisherID);
oci_execute($stid);
// to replace
$stid = WishDB::getInstance()->get_wishes_by_wisher_id($wisherID);
----
[start=4]
. Remova a linha que fecha a conexão do banco de dados.
[source,php]
----
// For MYSQL database
mysqli_close($con);
// For Oracle database
oci_close($con);
----
O código não é necessário porque a conexão ao banco de dados é automaticamente fechada quando o objeto WishDB é destruído. No entanto, mantenha o código que libera o recurso. É necessário liberar todos os recursos que usam uma conexão para garantir que a conexão seja fechada corretamente, mesmo quando a função `close` é chamada ou se a instância for destruída com a conexão do banco de dados.
[[refactoringCreateNewWisher]]
=== Refatorando o Arquivo createNewWisher.php
A refatoração não afetará o form de entrada HTML ou o código para exibir as mensagens de erro relacionadas.
1. Na parte superior do bloco <?php ?>, insira o código seguinte para permitir o uso do arquivo `db.php` :
[source,php]
----
require_once("Includes/db.php");
----
[start=2]
. Delete a credencial da conexão do banco de dados ( `$dbHost,` etc). Esses estão agora em `db.php.` .
[start=3]
. Substitua o código que estabelece conexão com o banco de dados e que obtém o wisher ID por uma chamada para a função `get_wisher_id_by_name` .
Para o *banco de dados MySQL*, o código a ser substituído é:
[source,php]
----
// to remove
$con = mysqli_connect("localhost", "phpuser", "phpuserpw");
if (!$con) {
exit('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
//set the default client character set
mysqli_set_charset($con, 'utf-8');
/** Check whether a user whose name matches the "user" field already exists */
mysqli_select_db($con, "wishlist");
$user = mysqli_real_escape_string($con, $_POST['user']);
$wisher = mysqli_query($con, "SELECT id FROM wishers WHERE name='".$user."'");
$wisherIDnum=mysqli_num_rows($wisher);
if ($wisherIDnum) {
$userNameIsUnique = false;
}
// to replace
$wisherID = WishDB::getInstance()->get_wisher_id_by_name($_POST["user"]);
if ($wisherID) {
$userNameIsUnique = false;
}
----
Para o *banco de dados Oracle*, o código a ser substituído é:
[source,php]
----
// to remove
$con = oci_connect("phpuser", "phpuserpw", "localhost/XE", "AL32UTF8");
if (!$con) {
$m = oci_error();
exit('Connect Error ' . $m['message']);
}
$query = "SELECT id FROM wishers WHERE name = :user_bv";
$stid = oci_parse($con, $query);
$user = $_POST['user'];
oci_bind_by_name($stid, ':user_bv', $user);
oci_execute($stid);
//Each user name should be unique. Check if the submitted user already exists.
$row = oci_fetch_array($stid, OCI_ASSOC);
if ($row) {
$userNameIsUnique = false;
}
// to replace
$wisherID = WishDB::getInstance()->get_wisher_id_by_name($_POST["user"]);
if ($wisherID) {
$userNameIsUnique = false;
}
----
O objeto `WishDB` existe enquanto a página atual estiver sendo processada. Ele é destruído depois que o processamento é concluído ou interrompido. O código para abrir uma conexão ao banco de dados não é necessário porque isso é feito pela função WishDB. O código para fechar a conexão não é necessário porque a conexão é fechada assim que o objeto `WishDB` é destruído.
[start=4]
. Substitua o código que insere novos desejos no banco de dados pelo código que chama a função `create_wisher` .
Para o *banco de dados MySQL*, o código a ser substituído é:
[source,php]
----
// to remove
if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !$password2IsEmpty && $passwordIsValid) {
$password = mysqli_real_escape_string($con, $_POST['password']);
mysqli_select_db($con, "wishlist");
mysqli_query($con, "INSERT wishers (name, password) VALUES ('" . $user . "', '" . $password . "')");
mysqli_free_result($wisher);
mysqli_close($con);
header('Location: editWishList.php');
exit;
}
// to replace
if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !$password2IsEmpty && $passwordIsValid) {
WishDB::getInstance()->create_wisher($_POST["user"], $_POST["password"]);
header('Location: editWishList.php' );
exit;
}
----
Para o *banco de dados Oracle*, o código a ser substituído é:
[source,php]
----
// to remove
if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !$password2IsEmpty && $passwordIsValid) {
$query = "INSERT INTO wishers (name, password) VALUES (:user_bv, :pwd_bv)";
$stid = oci_parse($con, $query);
$pwd = $_POST['password'];
oci_bind_by_name($stid, ':user_bv', $user);
oci_bind_by_name($stid, ':pwd_bv', $pwd);
oci_execute($stid);
oci_free_statement($stid);
oci_close($con);
header('Location: editWishList.php');
exit;
}
// to replace
if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !$password2IsEmpty && $passwordIsValid) {
WishDB::getInstance()->create_wisher($_POST["user"], $_POST["password"]);
header('Location: editWishList.php' );
exit;
}
----
== O código-fonte da Aplicação após a Lição Atual está Concluído
Usuários do MySQL: clique link:https://netbeans.org/projects/www/downloads/download/php%252Flesson4.zip[+aqui+] para fazer o download do código-fonte que reflete o estado do projeto depois que a lição estiver concluída.
Usuários do banco de dados Oracle: clique link:https://netbeans.org/projects/www/downloads/download/php%252Foracle-lesson4.zip[+aqui+] para fazer o download do código-fonte que reflete o estado do projeto depois que a lição for concluída.
== Próximas Etapas
link:wish-list-lesson3.html[+<< Lição anterior+]
link:wish-list-lesson5.html[+Próxima lição >>+]
link:wish-list-tutorial-main-page.html[+Voltar à página principal do Tutorial+]
== Links Úteis
Saiba mais sobre o uso de classes em PHP:
* link:http://us3.php.net/manual/en/language.oop5.php[+Classes e Objetos+]
Saiba mais sobre a refatoração de código PHP:
* link:http://www.slideshare.net/spriebsch/seven-steps-to-better-php-code-presentation/[+Sete Etapas Para Melhorar o Código PHP+]
* link:http://www.dokeos.com/wiki/index.php/Refactoring[+Refatoração do PHP+]
link:/about/contact_form.html?to=3&subject=Feedback:%20PHP%20Wish%20List%20CRUD%204:%20Optimizing%20Code[+Enviar Feedback neste Tutorial+]
Para enviar comentários e sugestões, obter suporte e manter-se informado sobre os desenvolvimentos mais recentes das funcionalidades de desenvolvimento PHP do NetBeans IDE, link:../../../community/lists/top.html[+junte-se à lista de correspondência users@php.netbeans.org+].
link:../../trails/php.html[+Voltar à Trilha de Aprendizado PHP+]