개발 꿀팁/PHP

PHP 8대 디자인 패턴

Jammie 2022. 6. 30. 17:34
반응형

PHP 네임스페이스
세대를 더 잘 조직할 수 있다코드, 자바의 패킷과 유사하다.

Test1.php
<?php
namespace Test1;//네임스페이스Test1
function test(){
    echo __FILE__;
}
Test2.php
<?php
namespace Test2; //네임스페이스Test2
function test(){
    echo __FILE__;//현재 파일이 있는 절대 경로 인쇄。
}
Test.php
<?php
require 'Test1.php';
require 'Test2.php';
Test1\test();//이렇게 해서 네임스페이스에 있는 메서드나 클래스를 사용합니다。Test1네임스페이스 표시,test()이 네임스페이스에 대한 메서드 보이기。
echo "<br>";
Test2\test();

실행 결과

요약: 위의 코드를 통해 서로 다른 네임스페이스에서 동일한 클래스 이름이나 메서드 이름을 가질 수 있음을 알 수 있습니다

클래스 자동 불러오기
PHP 프로젝트가 커질수록 하나의 PHP 파일 앞에 여러 의존적인 PHP 파일을 포함하는 require가 많아진다.한 클래스가 삭제되지만 다른 파일에 가져올 경우 치명적인 오류가 발생할 수 있습니다.위의 문제를 해결하는 방법이 __autoload() 함수입니다.

Test1.php
<?php
class Test1{
    static function test(){
        echo __FILE__;
    }
}
Test2.php
<?php
class Test2
{
    static function test(){
        echo __FILE__;
    }
}
Test.php
<?php
Test1::test();
Test2::test();

function __autoload($class){
    $dir  = __DIR__;
    $requireFile = $dir."\\".$class.".php";
    require $requireFile;
}

PHP는 이 코드를 사용하여 동적으로 파일을 불러옵니다.이 클래스가 파일에 포함되지 않은 경우 __autoload() 함수를 호출하여 파일을 동적으로 불러옵니다.그러나 여러 개의 프레임을 사용할 경우 각각의 프레임은 자체 __autoload( )로 구현되기 때문에 파일을 중복하여 가져올 수 있다

<?php
spl_autoload_register('autoload1');
spl_autoload_register('autoload2');
//문자열로 들어오는 자동 가져오기 기능을 사용하면 파일 중복으로 인한 오류 문제를 해결할 수 있습니다。
Test1::test();
Test2::test();

function autoload1($class){
    $dir  = __DIR__;
    $requireFile = $dir."\\".$class.".php";
    require $requireFile;
}
function autoload2($class){
    $dir  = __DIR__;
    $requireFile = $dir."\\".$class.".php";
    require $requireFile;
}

PSR-0
PHP의 네임스페이스는 절대 경로와 일치해야 한다.
유명의 이니셜을 대문자로 쓰다.
입력 파일을 제외한 다른 PHP 파일은 클래스여야 합니다. 아니오실행할 수 있는 코드가 있습니다.
디자인 패턴
단일 예제는 프로젝트 전체에서 하나의 개체 인스턴스를 만드는 방법입니다.문제, 공장 모델 해결new를 통해 인스턴스 객체를 생성하지 않는 방법이다.

단례 모드

1.$_instance는 정적 개인 변수로 선언해야 합니다
2.구조함수와 구조해석함수는 반드시 개인으로 선언하여 외부 프로그램을 방지해야 한다..new 클래스 단일 패턴의 의미 상실
3.getInstance() 메서드는 공통으로 설정해야 합니다, 이 방법을 불러와야 인스턴스의 참조를 반환할 수 있습니다.
4.:: 연산자는 정적 변수와 정적 함수만 접근할 수 있습니다.
5.new 오브젝트는 모두 메모리를 소모한다
6.사용 시나리오: 가장 많이 사용되는 곳은 데이터베이스 연결이다.
7.단일례 모드를 사용하여 객체를 생성하면 다른 객체가 생성될 수 있습니다.수많은 대상들이 사용하고 있다.
8.개인적인 __clone() 메서드 복제 방지
단일 예제 모드, 클래스 개체를 하나만 만들 수 있도록 합니다.컨스트럭터 private 수식,
static get Instance 방법 하나를 밝히고,메서드에서 개체의 인스턴스를 만듭니다.이 인스턴스가 이미 있으면 만들지 않습니다.예를 들어 데이터베이스 연결만 생성하면 됩니다。

공장 모델
공장 모델, 공장 방법 또는 클래스 생성 대상이지 코드에서 직선적이지 않습니다.new를 받다.
공장 모델을 사용하면 어떤 종류의 이름이나 방법을 바꿀 때 이를 피할 수 있다그 후, 이 클래스를 호출하는 모든 코드에서 이름이나 파라미터를 수정한다.

Test1.php
<?php
class Test1{
    static function test(){
        echo __FILE__;
    }
}

Factory.php
<?php
class Factory{
    /*
     * 만약 어떤 종류가 많은 파일들 중에서new ClassName(),그러면 혹시나 이런 이름이
     * 변경이 발생하거나 파라미터가 변화하여 공장 모델을 사용하지 않으면 하나하나를 수정해야 한다PHP
     * 코드, 공장 모델을 사용한 후에는 공장 종류나 방법만 수정하면 됩니다。
     */
    static function createDatabase(){
        $test = new Test1();
        return $test;
    }
}

Test.php
<?php
spl_autoload_register('autoload1');

$test = Factory::createDatabase();
$test->test();
function autoload1($class){
    $dir  = __DIR__;
    $requireFile = $dir."\\".$class.".php";
    require $requireFile;
}

Test1.php
<?php
class Test1{
    protected static  $tt;
    private function __construct(){}
    static function getInstance(){
        if(self::$tt){
            echo "개체가 생성됨<br>";
            return self::$tt;
        }else {
            self::$tt = new Test1();
            echo "개체 만들기<br>";
            return self::$tt;
        }
    }
     function echoHello(){
        echo "Hello<br>";
    }
}
Test.php
<?php
spl_autoload_register('autoload1');

$test = Test1::getInstance();
$test->echoHello();
$test = Test1::getInstance();
$test->echoHello();
$test = Test1::getInstance();
$test->echoHello();
$test = Test1::getInstance();
$test->echoHello();
function autoload1($class){
    $dir  = __DIR__;
    $requireFile = $dir."\\".$class.".php";
    require $requireFile;
}

등록 모드
등록 모드, 전역 공유 및 교환 객체 해결.이미 만들어진 오브젝트는 전역적으로 사용할 수 있는 배열에 걸고 필요할 때 그 배열에서 바로 가져오면 된다.대상을 전 세계의 나무에 등록하다.아무데나 직접 방문하다.

<?php

class Register
{
    protected static  $objects;
    function set($alias,$object)//대상을 전역 트리에 등록하다
    {
        self::$objects[$alias]=$object;//대상을 나무에 놓다
    }
    static function get($name){
        return self::$objects[$name];//트리에 등록된 개체 가져오기
    }
    function _unset($alias)
    {
        unset(self::$objects[$alias]);//트리에 등록된 개체를 제거합니다。
    }
}

어댑터 모드
서로 확연히 다른 다양한 함수 인터페이스를 통일된 API로 패키징한다.
PHP에서 데이터베이스 작업은 MySQL, MySQLi, PDO 세 가지가 있다.어댑터 패턴을 일치시켜 서로 다른 데이터베이스를 조작하고 동일한 API로 통일할 수 있다.유사한 시나리오에는 cache 어댑터가 있어 memcache, redis, file, apc 등 서로 다른 캐시 함수를 일치시킬 수 있다.
먼저 인터페이스를 정의한다(몇 가지 방법과 그에 상응하는 파라미터).그런 다음 몇 가지 다른 상황이 있을 때 몇 가지 클래스를 써서 인터페이스를 구현한다.비슷한 기능을 하는 함수를 만들어 일치시키는 방법으로 통일한다

인터페이스 IDatabase
<?php
namespace IMooc;
interface IDatabase
{
    function connect($host, $user, $passwd, $dbname);
    function query($sql);
    function close();
}
MySQL
<?php
namespace IMooc\Database;
use IMooc\IDatabase;
class MySQL implements IDatabase
{
    protected $conn;
    function connect($host, $user, $passwd, $dbname)
    {
        $conn = mysql_connect($host, $user, $passwd);
        mysql_select_db($dbname, $conn);
        $this->conn = $conn;
    }

    function query($sql)
    {
        $res = mysql_query($sql, $this->conn);
        return $res;
    }

    function close()
    {
        mysql_close($this->conn);
    }
}
MySQLi
<?php
namespace IMooc\Database;
use IMooc\IDatabase;
class MySQLi implements IDatabase
{
    protected $conn;

    function connect($host, $user, $passwd, $dbname)
    {
        $conn = mysqli_connect($host, $user, $passwd, $dbname);
        $this->conn = $conn;
    }

    function query($sql)
    {
        return mysqli_query($this->conn, $sql);
    }

    function close()
    {
        mysqli_close($this->conn);
    }
}
PDO
<?php
namespace IMooc\Database;
use IMooc\IDatabase;
class PDO implements IDatabase
{
    protected $conn;
    function connect($host, $user, $passwd, $dbname)
    {
        $conn = new \PDO("mysql:host=$host;dbname=$dbname", $user, $passwd);
        $this->conn = $conn;
    }
function query($sql)
    {
        return $this->conn->query($sql);
    }

    function close()
    {
        unset($this->conn);
    }
}

이상의 사례를 통해 PHP와 MySQL의 데이터베이스 인터랙션은 세 세트의 API를 사용하는데, 서로 다른 시나리오에서 다른 API를 사용할 수 있다면, 좋은 코드를 개발하고, 환경을 바꾸면 데이터베이스 API를 변경해야 할 수도 있다, 그러면 모든 코드를 고쳐 써야 한다, 어댑터 모드를 사용하면 통일된 API를 사용하여 하위 계층의 API 차이로 인한 환경 변화를 차단한 후 코드를 고쳐야 하는 문제가 있다.

전략 패턴
특정한 상황 환경에 적응하기 위해 특정한 행동과 알고리즘을 패키징하는 전략 모드.
eg:만약 온라인 쇼핑몰 시스템이 있다면, 남성, 여성 사용자를 위해 각각 다른 상품 카테고리로 옮겨야 하고, 모든 광고 코너에 다른 광고를 노출해야 합니다.전통적인 코드에서는 시스템에 각종 ifelse의 판단을 넣어 하드코딩하는 방식이다.언젠가 한 가지 가입자가 늘어나면 코드를 고쳐 써야 한다.정책 모드를 사용하면, 새로운 사용자 유형이 추가되면, 정책 하나만 추가하면 된다다른 모든 곳은 다른 전략만 쓰면 된다.
먼저 정책의 인터페이스 파일을 선언하고 정책이 포함된 행위를 약속한다.그 후, 각각의 구체적인 전략 실현 클래스를 정의한다.

UserStrategy.php
<?php
/*
 * 정책 파일의 인터페이스를 선언하고 정책에 포함된 행위를 약속합니다。
 */
interface UserStrategy
{
    function showAd();
    function showCategory();
}
FemaleUser.php
<?php
require_once 'Loader.php';
class FemaleUser implements UserStrategy
{
    function showAd(){
        echo "2016년 겨울 여성복";
    }
    function showCategory(){
        echo "여성복";
    }
}
MaleUser.php
<?php
require_once 'Loader.php';
class MaleUser implements UserStrategy
{
    function showAd(){
        echo "IPhone6s";
    }
    function showCategory(){
        echo "전자제품";
    }
}
Page.php//실행 파일
<?php
require_once 'Loader.php';
class Page
{
    protected $strategy;
    function index(){
        echo "AD";
        $this->strategy->showAd();
        echo "<br>";
        echo "Category";
        $this->strategy->showCategory();
        echo "<br>";
    }
    function setStrategy(UserStrategy $strategy){
        $this->strategy=$strategy;
    }
}

$page = new Page();
if(isset($_GET['male'])){
    $strategy = new MaleUser();
}else {
    $strategy = new FemaleUser();
}
$page->setStrategy($strategy);
$page->index();

실행 결과 그림:

요약:
이상과 같이 하는 것에 의해, 유저에 따라 로그인시에 다른 내용이 표시되지만, 표시시에 하드 코딩하는 문제가 해결되는 것을 알 수 있다.정책을 추가하려면 정책 구현 클래스를 추가한 다음 엔트리 파일에서 판단을 실행하여 해당 클래스를 가져옵니다.커플링을 풀다.
의존적 반전 및 제어 실현 (이해해야 함)
인터페이스를 통해 클래스와 클래스 간에 직접 의존하지 않도록 한다.인터페이스를 구현하는 클래스로 동적으로 들어오는 것은 클래스를 사용할 때 뿐입니다.클래스를 바꾸려면 인터페이스를 구현한 클래스를 제공하고 코드를 한 줄만 수정하면 됩니다.

관찰자 모드
1: 옵저버 모드(Observer)는 오브젝트의 상태가 변화하면 그에 의존하는 오브젝트가 모두 알림을 받고 자동으로 갱신됩니다.
2: 장면: 이벤트 발생 후 일련의 업데이트 작업을 수행합니다.전통적인 프로그래밍 방식은 사건의 코드 뒤에 바로 처리 논리를 넣는 방식이다.업데이트된 논리가 많아지면 코드가 유지되기 어려워진다.이 방식은 결합적이고, 침입적이며, 새로운 논리를 증가시키면 사건을 수정해야 한다주체 코드.
3: 관찰자 패턴은 저결합, 비침습적 통지 및 갱신 메커니즘을 실현한다.
이벤트 트리거 추상화 클래스 정의

EventGenerator.php
<?php
require_once 'Loader.php';
abstract class EventGenerator{
    private $observers = array();
    function addObserver(Observer $observer){
        $this->observers[]=$observer;
    }
    function notify(){
        foreach ($this->observers as $observer){
            $observer->update();
        }
    }
}

관찰자 인터페이스 정의

Observer.php
<?php
require_once 'Loader.php';
interface Observer{
    function update();//여기 바로 사건 발생 후 수행해야 할 논리가 있습니다
}
<?php
//하나가 실현되었다EventGenerator발생한 사건을 구체적으로 정의하기 위한 추상적인 클래스
require 'Loader.php';
class Event extends EventGenerator{
    function triger(){
        echo "Event<br>";
    }
}
class Observer1 implements Observer{
    function update(){
        echo "논리1<br>";
    }
}
class Observer2 implements Observer{
    function update(){
        echo "논리2<br>";
    }
}
$event = new Event();
$event->addObserver(new Observer1());
$event->addObserver(new Observer2());
$event->triger();
$event->notify();

어떤 사건이 발생한 후에 실행해야 하는 논리가 많아질 때, 논리를 느슨하게 결합하는 방식으로 첨삭할 수 있다.즉 코드 안의 붉은 부분은 관찰자 인터페이스를 구현한 클래스를 정의하고 복잡한 논리를 구현한 다음 붉은 부분에 코드 한 줄을 붙이면 된다.이렇게 해서 저결합을 실현했다.

원형 패턴
원형 모드 (객체 생성 시 소모되는 것을 피하기 위해 개체 복제)
1:공장 모드와 마찬가지로 객체를 생성하기 위한 모드입니다.
2: 공장 모델과 달리 먼저 하나의 객체를 만든 다음 clone을 통해 새로운 객체를 만듭니다.이렇게 하면 클래스를 만들 때 반복되는 초기화 작업이 사라집니다.
3: 시제품은 큰 객체를 생성하는데 사용되며, 큰 객체를 생성하는데 많은 오버헤드가 소요됩니다. 매번 new를 사용하면 많은 비용이 소요됩니다. 시제품은 메모리 복사본만 필요합니다.

Canvas.php
<?php
require_once 'Loader.php';
class Canvas{
private $data;
function init($width = 20, $height = 10)
    {
        $data = array();
        for($i = 0; $i < $height; $i++)
        {
            for($j = 0; $j < $width; $j++)
            {
                $data[$i][$j] = '*';
            }
        }
        $this->data = $data;
    }
function rect($x1, $y1, $x2, $y2)
    {
        foreach($this->data as $k1 => $line)
        {
            if ($x1 > $k1 or $x2 < $k1) continue;
           foreach($line as $k2 => $char)
            {
              if ($y1>$k2 or $y2<$k2) continue;
                $this->data[$k1][$k2] = '#';
            }
        }
    }

    function draw(){
        foreach ($this->data as $line){
            foreach ($line as $char){
                echo $char;
            }
            echo "<br>;";
        }
    }
}
Index.php
<?php
require 'Loader.php';
$c = new Canvas();
$c->init();
/ $canvas1 = new Canvas();
// $canvas1->init();
$canvas1 = clone $c;//복제를 통해 절약할 수 있다init()방법, 이 방법은 200번 순환한다.
//배열이 생성된다.아이템에 이런 오브젝트가 많이 생길 때 new가 많은 오브젝트, 그렇게
//성능이 많이 소모됩니다。
$canvas1->rect(2, 2, 8, 8);
$canvas1->draw();
echo "-----------------------------------------<br>";
// $canvas2 = new Canvas();
// $canvas2->init();
$canvas2 = clone $c;
$canvas2->rect(1, 4, 8, 8);
$canvas2->draw();

실행 결과:

장식기 모드
1: 데코레이션 모드, 클래스 수정 기능을 동적으로 추가할 수 있다
2: 하나의 클래스는 기능을 제공하는데, 이를 수정하여 추가하려는 경우,기존의 프로그래밍 방식에서는 하위 클래스를 써서 이를 계승하고 클래스를 구현하는 방법을 다시 써야 한다
3: 데코레이션 모드를 사용하면 런타임에 데코레이션 객체를 하나만 추가하면 됩니다.실현, 최대의 유연성 실현이 가능하다.

반응형