[MVC란? ]
MVC는 "세 부분(즉, MVC의 전체 이름, 모델, 뷰, 컨트롤러)"을 조화롭게 결합하여 복잡한 애플리케이션을 구성할 수 있도록 하는 개념입니다. 자동차는 실생활에서 MVC의 아주 좋은 예입니다. 자동차를 볼 때 우리는 내부와 외부라는 두 가지 View(디스플레이) 부분을 봅니다. 이 두 가지 모두 컨트롤러(드라이버)와 분리될 수 없습니다. 브레이크 시스템, 스티어링 휠 및 기타 제어 시스템은 모델을 나타냅니다. 이는 운전자(컨트롤러)로부터 제어 방법을 가져와 내부와 외부(뷰)에 적용합니다.
[웹상의 MVC]
MVC 프레임워크에서 다루는 개념은 매우 간단하고 매우 유연합니다. 기본 개념은 매개변수 요청을 기반으로 프레임워크 내의 모든 애플리케이션을 제어하는 단일 컨트롤러(예: index.php)가 있다는 것입니다. 이 컨트롤러에는 일반적으로 모델, 이벤트 및 GET 매개변수를 정의하는 매개변수가 (최소) 포함됩니다. 이런 방식으로 컨트롤러는 모든 요청을 승인하고 적절한 이벤트를 실행할 수 있습니다. 예를 들어, /index.php?module=foo&event=bar와 같은 요청은 아마도 foo라는 클래스를 로드한 다음 foo::bar()[bar( )함수]를 실행하는 데 사용됩니다. 이것의 장점은:
하나의 애플리케이션에서 수많은 코드를 유지하면서모든 애플리케이션에 대한 인터페이스를 유지하는 것이
매우 번거롭다는 것입니다. 각 코드에는 고유한 상대 경로, 데이터베이스 링크, 검증 등이 있기 때문입니다. 그렇게 하면 문제가 줄어들고 코드를 병합하고 재사용할 수 있습니다.
[왜 자신만의 MVC 프레임워크를 만들어야 할까요? ]
지금까지 PHP로 작성된 MVC 프레임워크를 많이 본 적이 없습니다. 사실, 제가 아는 것은 완전히 PHP5로 작성된 Solar라는 것뿐입니다. 다른 하나는 PHP의 RoR(Ruby on Rails - Ruby 언어용 오픈 소스 네트워크 프레임워크)이 되려고 하는 Cake입니다. 나 자신은 두 프레임워크 모두에 대해 약간의 불만을 가지고 있습니다. 그들은 PEAR, Smarty 등에 포함된 기존 코드를 활용하지 않습니다. 마지막으로 Solar는 대부분 한 사람이 작성한 프레임워크입니다. 저자 Paul이 좋은 사람이나 좋은 프로그래머가 아니라고 말할 의도는 없습니다.) 이러한 질문으로 인해 귀하가 이를 부정하지는 않을 것이며, 전혀 관심을 갖지 않을 가능성도 있습니다. 하지만 그렇기 때문에 최대한 많이 봐주시길 바랍니다.
[예전 방식]
2001년으로 돌아가서 작성한 코드를 보면 작성자가 template.txt라는 파일을 찾을 수 있는데 다음과 같습니다. www.phpv.net 재인쇄할 소스를 표시해 주세요
<?php
require_once('config.php'); // 기타 요구 사항, DB 정보 등
$APP_DB = 'mydb';
$APP_REQUIRE_LOGIN = false; // 스크립트에 로그인이 필요한 경우 true로 설정합니다.
$APP_TEMPLATE_FILE = 'foo.php'; // 스마트 템플릿
$APP_TITLE = '내 애플리케이션';
if ($APP_REQUIRE_LOGIN == true) {
if (!isset($_SESSION['userID'])) {
header("위치: /path/to/login.php");
출구();
}
}
$db = DB::connect('mysql://'.$DB_USER.':'.$DB_PASS.'@localhost/'.$APP_DB);
if (!PEAR::isError($db)) {
$db->setFetchMode(DB_FETCHMODE_ASSOC);
} 또 다른 {
die($db->getMessage());
}
// 여기에 논리를 넣으세요.
// 템플릿 출력
include_once(APP_TEMPLATE_PATH.'/header.php');
include_once(APP_TEMPLATE_PATH.'/'.$APP_TEMPLATE_FILE);
include_once(APP_TEMPLATE_PATH.'/footer.php');
?>
맙소사, 이 코드만 봐도 소름이 돋네요. 이 코드의 개념은 모든 애플리케이션이 이 처리 방법에 맞게 조정될 수 있도록 하는 것입니다. 예를 들어 template.txt를 myapp.php에 복사하고 몇 가지 변수를 변경하면 짜잔, 실행됩니다. 그럼에도 불구하고 이러한 고도로 조직화된 접근 방식에는 몇 가지 심각한 단점이 있습니다.
내 상사가 작성자가 myapp.php를 사용하여 어떤 경우에는 PDF, 어떤 경우에는 HTML, 어떤 경우에는 SOAP(XML 요청이 직접 제출됨)를 출력하기를 원했다면 어떻게 해야 할까요? 하다?
이 앱에 IMAP 또는 LDAP 인증이 필요한 경우 어떻게 해야 합니까?
다양한 유형의 코드(편집, 업그레이드, 삭제 포함)를 어떻게 처리합니까?
다단계 인증(관리자 및 비관리자)을 어떻게 처리합니까?
출력 캐싱을 활성화하려면 어떻게 해야 합니까? www.phpv.net 재인쇄할 소스를 알려주십시오.
[새로운 방식]
모든 것을 이 MVC 프레임워크에 넣으면 인생이 매우 단순하다는 것을 알게 될 것입니다. 다음 코드를 비교해 보세요:
<?php
myapp 클래스는 FR_Auth_User를 확장합니다.
{
공개 함수 __construct()
{
부모::__construct();
}
공개 함수 __default()
{
// 여기서 뭔가를 하세요
}
공개 함수 삭제()
{ }
공개 함수 __destruct()
{
부모::__destruct();
}
}
?>
이 코드는 데이터베이스에 연결하거나 사용자가 로그인했는지 확인하거나 다른 정보를 출력하는 데 사용되지는 않습니다. 컨트롤러에는 모든 것이 있습니다.
LDAP에 인증하려면 FR_Auth_LDAP를 설정할 수 있습니다. 컨트롤러는 특정 출력 방법(예: $_GET['output'])을 인식할 수 있으며 언제든지 PDF 또는 SOAP로 변환할 수 있습니다. 이벤트 핸들러 delete는 삭제만 담당하며 다른 작업에는 관심이 없습니다. 이 모듈에는 FR_User 클래스의 인스턴스가 있으므로 사용자의 로그인 여부 등을 간단히 확인할 수 있습니다. Smarty는 템플릿 엔진으로서 자연스럽게 캐시를 제어하지만 컨트롤러도 캐시의 일부를 제어할 수 있습니다.
앞서 언급한 기존 방식에서 MVC 방식으로 가는 것은 많은 사람들에게 새롭고 생소한 개념일 수 있지만, 한번 그러한 개념으로 전환하면 다시 전환하기가 상당히 어려울 것입니다.
[하단 레이어 구축]
저는 PEAR, 특히 PEAR_Error 클래스의 팬입니다. PHP5에는 PEAR_Error를 대체하는 새로운 내장 클래스 "Exception"이 도입되었습니다. 그러나 PEAR_Error에는 Exception보다 더 실용적인 기능이 있습니다. 따라서 이 기사 시리즈의 MVC 프레임워크 예제에서는 오류 처리에 이를 사용합니다. 어쨌든 생성자 자체에서는 오류를 다시 전달할 수 없기 때문에 생성자에서 오류를 가져오려면 Exception을 사용해야 합니다.
이러한 기본 클래스를 설계하는 목적은 다음과 같습니다.
PEAR를 사용하여 기본 클래스에 함수를 빠르게 추가하여
사용자가이
프레임워크에서 애플리케이션을 빠르게 개발할 수 있도록 작고 반복적으로 실용적인 추상 클래스를 생성합니다
.
클래스 계층 구조는 다음과 같습니다.
- FR_Object는 사용할 다른 모든 객체에 대한 기본 기능을 제공합니다(로깅, 일반 setFrom(), toArray() 포함)
- FR_Object_DB는 하위 클래스 및 기타 기능에 대한 데이터베이스 링크를 제공하는 작은 계층입니다.
- FR_Module은
다음과 같습니다.모든 애플리케이션의 하위 클래스(모듈, 모델 등이라고도 함)
- FR_Auth는 모든 확인 메커니즘의 하위 클래스입니다.
· FR_Auth_User는 사용자가 로그인했는지 여부를 확인해야 하는 모든 모듈을 확인하는 데 사용되는 확인 클래스입니다
. · FR_Auth_No는 다음과 같습니다. 유효성 검사가 필요하지 않은 모듈에 대한 모든 "가짜 유효성 검사 클래스"
- FR_Presenter는 로딩 및 표시를 처리하는 모든 응용 프로그램의 기본 클래스입니다
. - FR_Presenter_Smarty는 다양한 드라이브를 로드하는 기능을 포함하는 프레젠테이션 계층입니다. Smarty는 매우 좋은 템플릿 클래스입니다. 내장된 캐싱 메커니즘과 활성 개발 그룹이 있습니다. (역자 주: 이것은 분명히 광고입니다~)
· FR_Presenter_debug는 디버깅 부분의 표시 계층입니다. 이에 의존하여 개발자는 애플리케이션을 디버깅하고 디버깅할 수 있습니다
. FR_Presenter_rest는 개발자가 애플리케이션을 XML로 출력할 수 있도록 하는 REST 프리젠테이션 레이어입니다.
위의 기본 클래스 구조에서 이 MVC 프레임워크를 볼 수 있습니다. FR_Module은 모듈에 필요한 모든 것을 제공하는 반면 FR_Presenter는 다양한 표시 방법을 제공합니다. 이 시리즈의 다음 기사에서는 위의 기본 클래스를 모두 연결하는 컨트롤러를 만들겠습니다.
[코딩 표준]
정식으로 코드를 작성하기 전에 파트너(또는 자신)와 함께 앉아서 코딩 표준에 대해 논의(또는 생각)해야 합니다. MVC 프로그래밍의 전반적인 아이디어는 코드 재사용성(우연도 감소)과 코드 표준화라는 두 가지 사항을 중심으로 진행됩니다. 최소한 다음 사항을 고려해 볼 것을 권장합니다.
가장 먼저 고려해야 할 것은 변수 명명 및 약어 표준입니다. 이 때문에 파트너와 큰 싸움을 벌이지 마십시오. 그러나 일단 표준이 설정되면 처음부터 끝까지 따라야 하며, 특히 하위 수준 코드(기본 클래스)를 작성할 때는 더욱 그렇습니다.
모든 함수, 클래스 및 전역 변수에 사용할 표준 접두사를 사용자 정의합니다. 아쉽게도 PHP는 "네임스페이스(namespace)"를 지원하지 않습니다. 따라서 변수 이름과의 혼동과 충돌을 피하려면 접두사를 사용하는 것이 좋습니다. 나는 이 글 전체에서 "FR_"을 접두어로 사용할 것입니다.
[하위 레이어 작성]
파일 레벨 계획은 매우 중요합니다. 기본 계층적 계획은 간단하고 다소 엄격하게 정의되어 있습니다.
/
config.php
index.php
포함/
인증.php
인증/
No.php
사용자.php
모듈.php
객체.php
물체/
DB.php
발표자.php
증여자/
공통.php
debug.php
smarty.php
똑똑하다/
모듈/
예/
config.php
example.php
tpl/
example.tpl
tpl/
기본/
은닉처/
구성/
템플릿/
template_c/
이러한 파일 계층 구조는 많은 코드를 나타내야 한다고 생각할 수도 있습니다! 사실입니다. 하지만 해낼 수 있습니다. 시리즈가 끝나면 프로그래밍이 더 쉬워지고 개발 속도가 크게 향상된다는 것을 알게 될 것입니다.
파일 계층 구조에서 모든 기본 클래스는 포함 폴더에 있습니다. 각 기능 모듈은 구성 파일, 최소 하나의 모듈 파일 및 하나의 템플릿 파일을 사용합니다. 모든 모듈은 모듈 폴더에 포함되어 있습니다. 저는 템플릿 파일을 별도의 외부 폴더인 tpl 폴더에 배치하는 데 익숙해졌습니다.
config.php - 모든 전역 구성 변수를 포함하는 중앙 구성 파일입니다.
index.php - 컨트롤러에 대해서는 다음 글에서 자세히 설명하겠습니다.
object.php - 모든 기본 클래스의 기본 클래스로, 클래스에 필요한 대부분의 기능을 제공합니다. FR_Object_DB는 이 클래스를 상속하고 데이터베이스 링크를 제공합니다.
구조의 기본 개념은 모든 하위 클래스가 중앙 클래스에서 상속되어 모두 공통 기능을 공유하도록 하는 것입니다. 데이터베이스에 연결하는 기능을 FR_Object에 넣을 수 있지만 모든 클래스에 이 기능이 필요한 것은 아니기 때문에 FR_Object_DB에는 존재 이유가 있고 이에 대해서는 저자가 나중에 다루겠습니다.
<?php
require_once('Log.php')
/**
*FR_객체
*
* 프레임워크에서 사용하는 대부분의 클래스에 대한 기본 개체 클래스입니다.
* 기본 로깅 및 설정/가져오기 기능을 제공합니다.
*
* @저자 조 스텀프 < [email protected] >
* @packageFramework
*/
추상 클래스 FR_Object
{
/**
* $로그
*
* @var 혼합 $log PEAR 로그 인스턴스
*/
보호된 $log;
/**
*$나
*
* @var는 ReflectionClass의 $me 인스턴스를 혼합했습니다.
*/
보호된 $me;
/**
* __건설하다
*
* @저자 조 스텀프 < [email protected] >
* @접속 공개
*/
공개 함수 __construct()
{
$this->log = Log::factory('파일',FR_LOG_FILE);
$this->me = new ReflectionClass($this);
}
/**
* 세트에서
*
* @저자 조 스텀프 < [email protected] >
* @접속 공개
* @param 혼합 $data 인스턴스에 할당할 변수 배열
* @return 무효
*/
공개 함수 setFrom($data)
{
if (is_array($data) && count($data)) {
$valid = get_class_vars(get_class($this));
foreach ($var => $val로 $valid) {
if (isset($data[$var])) {
$this->$var = $data[$var];
}
}
}
}
/**
* 배열로
*
* @저자 조 스텀프 < [email protected] >
* @접속 공개
* @return 변수 이름으로 키가 지정된 멤버 변수의 혼합 배열
*/
공개 함수 toArray()
{
$defaults = $this->me->getDefaultProperties();
$return = 배열();
foreach ($defaults는 $var => $val) {
if ($this->$var 인스턴스of FR_Object) {
$return[$var] = $this->$var->toArray();
} 또 다른 {
$return[$var] = $this->$var;
}
}
$return을 반환;
}
/**
* __파괴
*
* @저자 조 스텀프 < [email protected] >
* @접속 공개
* @return 무효
*/
공개 함수 __destruct()
{
if ($this->log 인스턴스of 로그) {
$this->log->close();
}
}
}
?>
auth.php – 모든 인증 기능의 기본 클래스입니다. FR_Module에서 확장되었으며 주요 기능은 기본 검증 클래스의 작동 방식을 정의하는 것입니다.
FR_Module과 마찬가지로 일부 클래스는 데이터베이스에 연결할 필요가 없습니다. 마찬가지로 인증 기능이 필요하지 않은 클래스에도 FR_Auth_No를 생성하여 적용할 수 있습니다.
<?php
추상 클래스 FR_Auth는 FR_Module을 확장합니다.
{
// {{{ __건설하다()
함수__구조()
{
부모::__construct();
}
// }}}
// {{{ 인증()
추상 함수 authenticate();
// }}}
// {{{ __destruct()
함수 __destruct()
{
부모::__destruct();
}
// }}}
}
?>
module.php - 모든 모듈의 핵심
<?php
추상 클래스 FR_Module은 FR_Object_Web을 확장합니다.
{
// {{{ 속성
/**
* $발표자
*
* FR_Presenter::factory()에서 어떤 프리젠테이션(보기)을 결정하는 데 사용됩니다.
* 모듈에는 클래스를 사용해야 합니다.
*
* @저자 조 스텀프 < [email protected] >
* @var 문자열 $presenter
* @FR_Presenter, FR_Presenter_common, FR_Presenter_smarty 참조
*/
공개 $presenter = '똑똑함';
/**
* $데이터
*
* 최종적으로 뷰에 전달될 모듈에 의해 설정된 데이터입니다.
*
* @저자 조 스텀프 < [email protected] >
* @var 혼합 $data 모듈 데이터
* @ @see FR_Module::set(), FR_Module::getData()
*/
보호된 $data = array()
/**
* $이름
*
* @저자 조 스텀프 < [email protected] >
* @var string $name 모듈 클래스 이름
*/
공개 $이름
/**
* $tpl파일
*
* @저자 조 스텀프 < [email protected] >
* @var string $tplFile 템플릿 파일 이름
* @FR_Presenter_smarty 참조
*/
공개 $tplFile
/**
* $모듈이름
*
* @저자 조 스텀프 < [email protected] >
* @var string $moduleName 요청한 모듈 이름
* @FR_Presenter_smarty 참조
*/
공개 $moduleName = null;
/**
* $pageTemplate파일
*
* @저자 조 스텀프 < [email protected] >
* @var string $pageTemplateFile 외부 페이지 템플릿 이름
*/
공개 $pageTemplateFile = null;
// }}}
// {{{ __건설하다()
/**
* __건설하다
*
* @저자 조 스텀프 < [email protected] >
*/
공개 함수 __construct()
{
부모::__construct();
$this->name = $this->me->getName();
$this->tplFile = $this->name.'.tpl';
}
// }}}
// {{{ __기본()
/**
* __기본
*
* 이 함수는 이벤트가 지정되지 않은 경우 컨트롤러에 의해 실행됩니다.
* 사용자의 요청에 따라.
*
* @저자 조 스텀프 < [email protected] >
*/
추상 공용 함수 __default();
// }}}
// {{{ set($var,$val)
/**
* 세트
*
* 모듈에 대한 데이터를 설정하면 결국 모듈에 전달됩니다.
* FR_Module::getData()를 통한 프리젠터 클래스.
*
* @저자 조 스텀프 < [email protected] >
* @param string $var 변수 이름
* @param 혼합 $val 변수 값
* @return 무효
* @FR_Module::getData() 참조
*/
보호된 함수 set($var,$val) {
$this->data[$var] = $val;
}
// }}}
// {{{ getData()
/**
*getData
*
* 모듈의 데이터를 반환합니다.
*
* @저자 조 스텀프 < [email protected] >
* @return 혼합
* @FR_Presenter_common 참조
*/
공개 함수 getData()
{
$this->data를 반환합니다.
}
// }}}
// {{{ isValid($module)
/**
*유효함
*
* $module이 유효한 프레임워크 모듈인지 확인합니다.
* 모듈이 프레임워크에 적합한지 확인하기 위한 컨트롤러
* 금형. FR_Module과 FR_Auth 모두에서 확장되는 경우
*달리기 좋다.
*
* @저자 조 스텀프 < [email protected] >
* @정적
* @param 혼합 $module
* @return 부울
*/
공개 정적 함수 isValid($module)
{
반환 (is_object($module) &&
$module 인스턴스of FR_Module &&
FR_Auth의 $모듈 인스턴스);
}
// }}}
// {{{ __destruct()
공개 함수 __destruct()
{
부모::__destruct();
}
// }}}
}
?>
Presenter.php - 프리젠테이션 레이어의 핵심입니다.
<?php
클래스 FR_Presenter
{
// {{{ 공장($type,FR_Module $module)
/**
*공장
*
* @저자 조 스텀프 < [email protected] >
* @접속 공개
* @param string $type 표현 유형(우리의 관점)
* @param mix $module 발표자가 표시할 모듈
* 실패 또는 유효한 발표자에 대한 @return 혼합 PEAR_Error
* @정적
*/
정적 공용 함수 팩토리($type,FR_Module $module)
{
$file = FR_BASE_PATH.'/includes/Presenter/'.$type.'.php';
if (include($file)) {
$class = 'FR_Presenter_'.$type;
if (class_exists($class)) {
$프레젠터 = 새로운 $class($module);
if ($presenter 인스턴스of FR_Presenter_common) {
$presenter를 반환합니다.
}
return PEAR::raiseError('잘못된 프리젠테이션 클래스: '.$type);
}
return PEAR::raiseError('프레젠테이션 클래스를 찾을 수 없습니다: '.$type);
}
return PEAR::raiseError('발표자 파일을 찾을 수 없습니다: '.$type);
}
// }}}
}
?>
다음 글에서는 컨트롤러(이 글에서는 MVC의 Controller, index.php)의 구조를 소개하겠습니다. 세 번째 글에서는 프리젠테이션 레이어(MVC에서 보기)에 대해 소개하겠습니다. 네 번째 글에서는 특정 모듈을 예로 들어 애플리케이션(MVC의 모듈 또는 모델)을 생성하겠습니다.