[O que é MVC? 】
MVC é um conceito que permite combinar harmoniosamente "três partes (ou seja, o nome completo de MVC, Modelo, Visualização e Controlador)" para formar um aplicativo complexo. Um carro é um bom exemplo de MVC na vida real. Quando olhamos para um carro, olhamos para duas partes do View (display): interior e exterior. Ambos são inseparáveis de um Controlador: o driver. O sistema de freios, volante e outros sistemas de controle representam o Modelo: eles pegam os métodos de controle do motorista (Controlador) e os aplicam ao interior e ao exterior (Visualização).
[MVC na Web]
Os conceitos cobertos pelo framework MVC são bastante simples e extremamente flexíveis. O conceito básico é que você tenha um único controlador (como index.php) que controla todos os aplicativos dentro da estrutura baseados em solicitações de parâmetros. Este controlador geralmente contém (minimamente) um parâmetro que define o modelo, um evento e um parâmetro GET. Desta forma, o controlador pode reconhecer todas as solicitações e executar os eventos apropriados. Por exemplo, uma solicitação como esta /index.php?module=foo&event=bar é provavelmente usada para carregar uma classe chamada foo e então executar foo::bar()[que é a função bar()]. As vantagens disso são:
manter uma interface para todos os aplicativos
enquanto mantém inúmeros códigos em um aplicativo é muito problemático, porque cada trecho de código tem seu próprio caminho relativo, link de banco de dados, verificação, etc. Fazer isso evita problemas e permite mesclar e reutilizar código
[Por que criar sua própria estrutura MVC? 】
Até agora, não vi muitos frameworks MVC escritos em PHP. Na verdade, só conheço um - Solar, que é totalmente escrito em PHP5. O outro é o Cake, que está tentando ser RoR (Ruby on Rails - um framework de rede de código aberto para a linguagem Ruby) do PHP. Eu mesmo tenho alguma insatisfação com ambos os frameworks: eles não aproveitam o código existente incluído no PEAR, Smarty, etc.; o Cake atual ainda é relativamente confuso, finalmente, o Solar é um framework escrito principalmente por uma pessoa. nenhuma intenção de dizer que seu autor, Paul, não é uma boa pessoa ou um bom programador). Essas perguntas provavelmente não fazem você negá-las, e é provável que você nem se importe com elas. Mas por causa disso, peço que você os observe o máximo possível.
[Maneira antiga]
Se você voltar a 2001 e olhar o código que você escreveu, o autor poderá encontrar um arquivo chamado template.txt, que se parece com isto: www.phpv.net Por favor, indique a fonte para reimpressão
<?php
require_once('config.php'); // Outros requisitos, informações do banco de dados, etc.
$APP_DB = 'mydb';
$APP_REQUIRE_LOGIN = false; // Defina como verdadeiro se o script exigir login
$APP_TEMPLATE_FILE = 'foo.php'; // Modelo inteligente
$APP_TITLE = 'Meu Aplicativo'
if ($APP_REQUIRE_LOGIN == true) {
if (!isset($_SESSION['userID'])) {
header("Localização: /caminho/para/login.php");
saída();
}
}
$db = DB::connect('mysql://'.$DB_USER.':'.$DB_PASS.'@localhost/'.$APP_DB);
if (!PEAR::isError($db)) {
$db->setFetchMode(DB_FETCHMODE_ASSOC);
} outro {
morrer($db->getMessage());
}
//Coloque sua lógica aqui
// Gera o modelo
include_once(APP_TEMPLATE_PATH.'/header.php');
include_once(APP_TEMPLATE_PATH.'/'.$APP_TEMPLATE_FILE);
include_once(APP_TEMPLATE_PATH.'/footer.php');
?>
Oh meu Deus, só de olhar para esse código me dá arrepios. O conceito deste código é garantir que cada aplicativo possa ser adaptado a este método de processamento. Por exemplo, posso simplesmente copiar template.txt para myapp.php, alterar algumas variáveis e pronto, ele será executado. Ainda assim, essa abordagem altamente organizada tem algumas desvantagens sérias: e
se meu chefe quisesse que o autor usasse myapp.php para gerar PDF em alguns casos, HTML em alguns casos e SOAP em alguns casos (solicitações XML enviadas diretamente), o que eu faço? fazer?
O que devo fazer se este aplicativo exigir autenticação IMAP ou LDAP?
Como lidar com os diferentes tipos de código (incluindo edições, atualizações e exclusões)?
Como lidar com a autenticação multinível (administrador versus não administrador)?
Como habilito o cache de saída? www.phpv.net Por favor, indique a fonte para reimpressão
[Nova maneira]
Jogue tudo nesta estrutura MVC e você descobrirá que a vida é muito simples. Por favor compare o seguinte código:
<?php
classe myapp estende FR_Auth_User
{
função pública __construct()
{
pai::__construir();
}
função pública __default()
{
// Faça algo aqui
}
função pública excluir()
{ }
função pública __destruct()
{
pai::__destruct();
}
}
?>
Observe que esse código obviamente não é usado para vincular um banco de dados, determinar se um usuário está logado ou gerar qualquer outra informação. O controlador tem tudo.
Se eu quiser autenticar no LDAP, posso estabelecer FR_Auth_LDAP. O controlador pode reconhecer certos métodos de saída (como $_GET['output']) e pode converter para PDF ou SOAP a qualquer momento. O manipulador de eventos delete é responsável apenas pela exclusão e não se preocupa com mais nada. Como este módulo possui uma instância da classe FR_User, ele pode simplesmente determinar se um usuário está logado, etc. O Smarty, como mecanismo de modelo, controla naturalmente o cache, mas o controlador também pode controlar parte do cache.
Passar do método antigo mencionado anteriormente para o método MVC pode ser um conceito novo e desconhecido para muitas pessoas, mas depois que você mudar para esse conceito, será muito difícil voltar atrás.
[Construir a camada inferior]
Sou fã do PEAR, especialmente da classe PEAR_Error. PHP5 introduz uma nova classe interna "Exception" que substitui PEAR_Error. Mas PEAR_Error possui alguns recursos mais práticos que Exception. Portanto, os exemplos de estrutura MVC nesta série de artigos irão utilizá-la para tratamento de erros. De qualquer forma, ainda preciso usar Exception para obter o erro do construtor, já que eles próprios não podem devolver o erro.
O objetivo de projetar essas classes básicas é o seguinte:
Use PEAR para adicionar funções rapidamente às classes básicas
para criar classes abstratas pequenas e repetidamente práticas, para que os usuários possam desenvolver rapidamente aplicativos nesta estrutura.
Use
phpDocumentor para gerar documentos para todas as classes básicas.
a hierarquia de classes será semelhante a esta:
- FR_Object fornecerá funcionalidade básica para todos os outros objetos usarem (incluindo registro, setFrom(), toArray())
- FR_Object_DB é uma pequena camada que fornece links de banco de dados para subclasses e outras funções
- FR_Module é a classe inferior de todos os aplicativos (também chamados de módulos, modelos, etc.)
- FR_Auth é a classe inferior de todos os mecanismos de verificação
· FR_Auth_User é uma classe de verificação usada para verificar todos os módulos que precisam verificar se o usuário está logado
· FR_Auth_No é todas as "classes de validação falsas" para módulos que não requerem validação
- FR_Presenter é a classe subjacente para todos os aplicativos que lidam com carregamento e exibição
- FR_Presenter_Smarty é a camada de apresentação que inclui a capacidade de carregar unidades diferentes. Smarty é uma classe de modelo muito boa. Ela possui um mecanismo de cache integrado e um grupo de desenvolvimento ativo (Nota do tradutor: isso é obviamente um anúncio ~)
· FR_Presenter_debug é a camada de exibição da parte de depuração. Confiando nele, os desenvolvedores podem depurar aplicativos e depurá-los
. FR_Presenter_rest é uma camada de apresentação REST que permite aos desenvolvedores gerar aplicativos em XML.
A partir da estrutura de classe básica acima, você poderá ver esta estrutura MVC. FR_Module fornece tudo o que o módulo precisa, enquanto FR_Presenter fornece diferentes métodos de exibição. No próximo artigo desta série, criarei um controlador que une todas as classes base acima.
[Padrões de codificação]
Antes de escrever código formalmente, você deve sentar e discutir (ou pensar sobre) padrões de codificação com seus parceiros (ou com você mesmo). A ideia geral da programação MVC gira em torno de dois pontos: reutilização de código (redução de coincidências) e padronização de código. Recomendo pelo menos os seguintes pontos a serem considerados:
A primeira coisa a considerar são os padrões de nomenclatura e abreviação de variáveis. Não entre em uma grande briga com seus parceiros por causa disso, mas uma vez definidos os padrões, eles devem ser seguidos do começo ao fim, principalmente ao escrever código de baixo nível (classes base).
Personalize um prefixo padrão para usar em todas as funções, classes e variáveis globais. Infelizmente, o PHP não suporta "namespace (namespace)". Portanto, para evitar confusão e conflitos com nomes de variáveis, é aconselhável usar um prefixo. Usarei "FR_" como prefixo ao longo deste artigo.
[Escrevendo a camada inferior]
O planejamento em nível de arquivo é muito importante. O planejamento hierárquico básico é simples e bem definido:
/
config.php
index.php
inclui/
Autenticação.php
Autorização/
Não.php
Usuário.php
Módulo.php
Objeto.php
Objeto/
DB.php
Apresentador.php
Apresentador/
comum.php
depuração.php
inteligente.php
Esperto/
módulos/
exemplo/
config.php
exemplo.php
tpl/
exemplo.tpl
tpl/
padrão/
cache/
configuração/
modelos/
templates_c/
Você pode pensar que tal hierarquia de arquivos deve representar muito código! É verdade, mas você pode fazer isso. Ao final da série, você descobrirá que sua programação ficará mais fácil e sua velocidade de desenvolvimento melhorará bastante.
Na hierarquia de arquivos, todas as classes básicas estão na pasta include. Cada módulo funcional utiliza um arquivo de configuração, pelo menos um arquivo de módulo e um arquivo de modelo. Todos os módulos estão contidos na pasta de módulos. Acostumei-me a colocar arquivos de modelo em uma pasta externa separada, a pasta tpl.
config.php - o arquivo de configuração central, contendo todas as variáveis de configuração globais.
index.php - Controlador, será descrito em detalhes no próximo artigo.
object.php - a classe subjacente para todas as classes básicas, fornecendo a maior parte da funcionalidade necessária à classe. FR_Object_DB herda esta classe e fornece links de banco de dados.
O conceito básico de uma estrutura é fazer com que todas as subclasses herdem de uma classe central, de modo que todas compartilhem algumas características comuns. Você pode colocar a função de vinculação ao banco de dados em FR_Object, mas nem todas as classes precisam dessa função, então FR_Object_DB tem uma razão de existência, e o autor discutirá isso mais tarde.
<?php
require_once('Log.php')
;
*FR_Objeto
*
* A classe de objeto base para a maioria das classes que usamos em nosso framework.
* Fornece registro básico e funcionalidade set/get.
*
* @autor Joe Stump < [email protected] >
* @packageFramework
*/
classe abstrata FR_Object
{
/**
*$log
*
* @var misto $log Instância do Log PEAR
*/
protegido $log;
/**
*$me
*
* @var misto $me Instância de ReflectionClass
*/
protegido $me;
/**
* __construir
*
* @autor Joe Stump < [email protected] >
* @acessar público
*/
função pública __construct()
{
$this->log = Log::factory('arquivo',FR_LOG_FILE);
$this->me = new ReflectionClass($this);
}
/**
* definirDe
*
* @autor Joe Stump < [email protected] >
* @acessar público
* @param mixed $data Array de variáveis para atribuir à instância
* @return nulo
*/
função pública setFrom($dados)
{
if (is_array($dados) && contagem($dados)) {
$ válido = get_class_vars(get_class($this));
foreach ($válido como $var => $val) {
if (isset($dados[$var])) {
$this->$var = $dados[$var];
}
}
}
}
/**
* paraArray
*
* @autor Joe Stump < [email protected] >
* @acessar público
* @return array misto de variáveis de membro codificadas por nome de variável
*/
função pública toArray()
{
$defaults = $this->me->getDefaultProperties();
$return=array();
foreach ($padrão como $var => $val) {
if ($this->$var instância de FR_Object) {
$return[$var] = $this->$var->toArray();
} outro {
$return[$var] = $this->$var;
}
}
retornar $ retorno;
}
/**
* __destruir
*
* @autor Joe Stump < [email protected] >
* @acessar público
* @return nulo
*/
função pública __destruct()
{
if ($this->log instanceof Log) {
$this->log->close();
}
}
}
?>
auth.php – Esta é a classe subjacente para todas as funcionalidades de autenticação. É estendido de FR_Module e sua principal função é definir como funciona uma classe básica de verificação.
Assim como FR_Module, algumas classes não precisam estar conectadas ao banco de dados. Da mesma forma, FR_Auth_No pode ser criado e aplicado a classes que não requerem funções de autenticação.
<?php
classe abstrata FR_Auth estende FR_Module
{
// {{{ __construir()
função__construir()
{
pai::__construir();
}
// }}}
// {{{autenticação()
função abstrata autenticar();
// }}}
// {{{ __destruct()
função __destruct()
{
pai::__destruct();
}
// }}}
}
?>
module.php - o coração de todos os módulos
<?php
classe abstrata FR_Module estende FR_Object_Web
{
// {{{ propriedades
/**
*$apresentador
*
* Usado em FR_Presenter::factory() para determinar qual apresentação (visualização)
*classe deve ser usada para o módulo.
*
* @autor Joe Stump < [email protected] >
* @var string $presenter
* @ver FR_Presenter, FR_Presenter_common, FR_Presenter_smarty
*/
public $presenter = 'espertinho';
/**
*$dados
*
* Dados definidos pelo módulo que eventualmente serão passados para a view.
*
* @autor Joe Stump < [email protected] >
* @var dados mistos do módulo $data
* @see FR_Module::set(), FR_Module::getData()
*/
dados $protegidos = array()
;
* $nome
*
* @autor Joe Stump < [email protected] >
* @var string $name Nome da classe do módulo
*/
público $nome;
/**
*$tplArquivo
*
* @autor Joe Stump < [email protected] >
* @var string $tplFile Nome do arquivo de modelo
* @see FR_Presenter_smarty
*/
public $tplArquivo;
/**
*$moduleName
*
* @autor Joe Stump < [email protected] >
* @var string $moduleName Nome do módulo solicitado
* @see FR_Presenter_smarty
*/
public $moduleName = null;
/**
*$pageTemplateFile
*
* @autor Joe Stump < [email protected] >
* @var string $pageTemplateFile Nome do modelo de página externa
*/
public $pageTemplateFile = null;
// }}}
// {{{ __construct()
/**
* __construir
*
* @autor Joe Stump < [email protected] >
*/
função pública __construct()
{
pai::__construir();
$this->nome = $this->me->getNome();
$this->tplFile = $this->nome.'.tpl';
}
// }}}
// {{{ __padrão()
/**
* __padrão
*
* Esta função é executada pelo controlador se um evento não for especificado
* na solicitação do usuário.
*
* @autor Joe Stump < [email protected] >
*/
função pública abstrata __default();
// }}}
// {{{set($var,$val)
/**
* definir
*
* Defina os dados para o seu módulo. Isso eventualmente será passado para o módulo.
* classe apresentadora via FR_Module::getData().
*
* @autor Joe Stump < [email protected] >
* @param string $var Nome da variável
* @param misto $val Valor da variável
* @return nulo
* @see FR_Module::getData()
*/
conjunto de funções protegidas($var,$val) {
$this->dados[$var] = $val;
}
// }}}
// {{{ getData()
/**
*obterDados
*
* Retorna os dados do módulo.
*
* @autor Joe Stump < [email protected] >
* @return misto
* @see FR_Presenter_common
*/
função pública getData()
{
retorne $este->dados;
}
// }}}
// {{{ isValid($módulo)
/**
*é válido
*
* Determina se $module é um módulo de framework válido.
* o controlador para determinar se o módulo se encaixa no nosso framework
* molde. Se se estender de FR_Module e FR_Auth então deveria ser.
*bom para correr.
*
* @autor Joe Stump < [email protected] >
* @estático
* @param misto $módulo
* @return bool
*/
função estática pública isValid($module)
{
return (é_objeto($módulo) &&
$module instância de FR_Module &&
$módulo instância de FR_Auth);
}
// }}}
// {{{ __destruct()
função pública __destruct()
{
pai::__destruct();
}
// }}}
}
?>
presenter.php - o núcleo da camada de apresentação.
<?php
classe FR_Presenter
{
// {{{fábrica($tipo,FR_Module $módulo)
/**
*fábrica
*
* @autor Joe Stump < [email protected] >
* @acessar público
* @param string $type Tipo de apresentação (nossa visão)
* @param mixed $module Nosso módulo, que o apresentador irá exibir
* @return misto PEAR_Error em caso de falha ou apresentador válido
* @estático
*/
fábrica de função pública estática($type,FR_Module $module)
{
$arquivo = FR_BASE_PATH.'/includes/Presenter/'.$type.'.php';
if (include($arquivo)) {
$class = 'FR_Presenter_'.$type;
if (class_exists($classe)) {
$apresentador = new $class($módulo);
if ($presenter instanceof FR_Presenter_common) {
return $apresentador;
}
return PEAR::raiseError('Classe de apresentação inválida: '.$type);
}
return PEAR::raiseError('Classe de apresentação não encontrada: '.$type);
}
return PEAR::raiseError('Arquivo do apresentador não encontrado: '.$type);
}
// }}}
}
?>
No próximo artigo apresentarei a estrutura do controlador (Controller em MVC, index.php neste artigo). No terceiro artigo apresentarei a camada de apresentação (Visualização em MVC). No quarto artigo utilizarei um módulo específico como exemplo para criar uma aplicação (Módulo ou Modelo em MVC).