분류 php

바닐라 PHP에서 CLI PHP 애플리케이션 부트 스트랩

컨텐츠 정보

  • 조회 464 (작성일 )

본문

소개 


PHP는 웹 응용 프로그램 및 CMS에서 널리 사용되는 것으로 잘 알려져 있지만 많은 사람들이 모르는 것은 PHP가 웹 서버가 필요 없는 명령줄 응용 프로그램을 작성하기 위한 훌륭한 언어라는 것입니다. 


사용하기 쉽고 친숙한 구문으로 인해 API와 통신하거나 Crontab을 통해 예약 된 작업을 실행할 수 있지만 외부 사용자에게 노출 될 필요가 없는 무료 도구 및 작은 응용 프로그램을 위한 낮은 언어입니다.


원본 : https://dev.to/erikaheidi/bootstrapping-a-cli-php-application-in-vanilla-php-4ee


확실히, 당신은 당신의 요구에 부응하기 위해 하나의 파일 PHP 스크립트를 만들 수 있으며 작은 것들에 대해서는 합리적으로 잘 작동 할 것입니다; 그러나 앞으로 해당 코드를 유지 관리, 확장 또는 재사용 하기가 매우 어렵습니다.

우리가 더 이상 프론트 엔드를 사용하지 않는 것을 제외하고는 명령 줄 응용 프로그램을 구축 할 때 동일한 웹 개발 원칙을 적용 할 수 있습니다. 

또한 외부 사용자가 응용 프로그램에 액세스 할 수 없으므로 보안이 강화되고 실험을 위한 더 많은 공간이 만들어집니다.


나는 웹 응용 프로그램이 조금 아프고 최근에 프론트 엔드 주변에 구축되는 복잡성 때문에 명령 줄에서 PHP를 사용하는 것은 개인적으로 매우 상쾌했습니다. 이 포스트 / 시리즈에서는 PHP에서 실험용 CLI 앱의 기본으로 사용할 수 있는 미니멀리스트 / 종속성이 없는 CLI AppKit (작은 프레임 워크를 생각 함) (minicli)을 함께 빌드 합니다.


추신 : 필요한 모든 것이 git clone 인 경우 여기로 이동하십시오.


이것은 minicli 빌딩 시리즈의 1 부입니다.


전제 조건 


이 튜토리얼을 따르려면 로컬 컴퓨터 또는 개발 서버에 php-cli가 설치되어 있고 자동 로드 파일을 생성하려면 Composer가 필요합니다.


1. 디렉토리 구조 및 진입 점 설정 


메인 프로젝트 디렉토리를 만들어 시작해 봅시다 :


mkdir minicli
cd minicli


다음으로 CLI 응용 프로그램의 진입 점을 만듭니다. 이것은 최신 PHP 웹 앱의 index.php 파일과 동일합니다. 

여기서 단일 진입 점은 요청을 관련 컨트롤러로 리디렉션합니다. 그러나 애플리케이션은 CLI 전용이므로 다른 파일 이름을 사용하고 웹 서버에서의 실행을 허용하지 않는 몇 가지 안전 장치를 포함합니다.


자주 사용하는 텍스트 편집기를 사용하여 minicli라는 새 파일을 엽니다.


vim minicli


여기에 .php 확장자가 포함되어 있지 않습니다. 명령 행에서 이 스크립트를 실행하고 있으므로 쉘 프로그램에 PHP를 사용하여 이 스크립트를 실행하고 있음을 알려주는 특수 디스크립터를 포함 시킬 수 있습니다.


#!/usr/bin/php
<?php

if (php_sapi_name() !== 'cli') {
    exit;
}

echo "Hello World\n";


첫 번째 줄은 응용 프로그램 shebang입니다. 이 스크립트를 실행하는 쉘에게 /usr/bin/php를 해당 코드의 인터프리터로 사용하도록 지시합니다.


chmod를 사용하여 스크립트를 실행 가능하게 만드십시오.


chmod +x minicli

이제 다음을 사용하여 응용 프로그램을 실행할 수 있습니다.


./minicli


Hello World가 출력으로 표시되어야 합니다.


2. 소스 디렉토리 및 자동로드 설정 


여러 프레임 워크에서 이 프레임 워크를 쉽게 재사용 할 수 있도록 다음 두 가지 소스 디렉토리를 작성합니다.

  • app :이 네임 스페이스는 응용 프로그램 별 모델 및 컨트롤러 용으로 예약됩니다.
  • lib :이 네임 스페이스는 핵심 프레임 워크 클래스에서 사용되며 다양한 애플리케이션에서 재사용 할 수 있습니다.

다음을 사용하여 두 디렉토리를 작성하십시오.


mkdir app
mkdir lib

이제 자동 로드를 설정하기 위해 composer.json 파일을 만들어 봅시다. 이를 통해 PHP의 클래스 및 기타 객체 지향 리소스를 사용하면서 응용 프로그램을 보다 잘 구성 할 수 있습니다.


텍스트 편집기에서 새 composer.json 파일을 작성하고 다음 컨텐츠를 포함하십시오.


{
  "autoload": {
    "psr-4": {
      "Minicli\\": "lib/",
      "App\\": "app/"
    }
  }
}

파일을 저장하고 닫은 후 다음 명령을 실행하여 자동 로드 파일을 설정하십시오.


composer dump-autoload

자동 로드가 예상대로 작동하는지 테스트하기 위해 첫 번째 클래스를 작성합니다. 이 클래스는 명령 실행 처리를 담당하는 Application 객체를 나타냅니다. 우리는 간단하게 유지하고 이름을 App으로 지정합니다.


선택한 텍스트 편집기를 사용하여 lib 폴더 내에 새 App.php 파일을 작성하십시오.


vim lib/App.php

App 클래스는 이전에 minicli 실행 파일에서 설정 한 "Hello World"코드를 대체하는 runCommand 메소드를 구현합니다. 나중에 이 명령을 수정하여 여러 명령을 처리 할 수 ​​있습니다. 지금은 스크립트를 실행할 때 전달 된 매개 변수를 사용하여 "Hello $ name"텍스트를 출력합니다. 매개 변수가 전달되지 않으면 $ name 변수의 기본값으로 world가 사용됩니다.


App.php 파일에 다음 내용을 삽입하고 완료되면 파일을 저장하고 닫습니다.

<?php

namespace Minicli;

class App
{
    public function runCommand(array $argv)
    {
        $name = "World";
        if (isset($argv[1])) {
            $name = $argv[1];
        }

        echo "Hello $name!!!\n";
    }
}


이제 minicli 스크립트로 이동하여 현재 내용을 다음 코드로 바꾸십시오.이 코드는 잠시 후에 설명합니다.


#!/usr/bin/php
<?php

if (php_sapi_name() !== 'cli') {
    exit;
}

require __DIR__ . '/vendor/autoload.php';

use Minicli\App;

$app = new App();
$app->runCommand($argv);

여기서는 새 객체를 만들 때 클래스 파일을 자동으로 포함하기 위해 자동 생성 autoload.php 파일이 필요합니다. App 객체를 만든 후 runCommand 메서드를 호출하여 해당 스크립트를 실행할 때 사용되는 모든 매개 변수가 포함 된 전역 $ argv 변수를 전달합니다. $ argv 변수는 첫 번째 위치 (0)가 스크립트의 이름이고 후속 위치는 명령 호출에 전달 된 추가 매개 변수로 채워지는 배열입니다. 

이것은 명령 행에서 실행되는 PHP 스크립트에서 사용 가능한 사전 정의 된 변수입니다.


이제 모든 것이 예상대로 작동하는지 테스트하려면 다음을 실행하십시오.


./minicli your-name


그리고 다음과 같은 결과가 나타납니다.


Hello your-name!!!


이제 스크립트에 추가 매개 변수를 전달하지 않으면 다음과 같이 인쇄됩니다.


Hello World!!!


3. 출력 도우미 만들기 


명령 행 인터페이스는 텍스트 전용이므로 때때로 응용 프로그램의 오류 또는 경고 메시지를 식별하거나 사람이 읽을 수있는 방식으로 데이터를 형식화 하기가 어려울 수 있습니다. 이러한 작업 중 일부를 터미널로의 출력을 처리하는 도우미 클래스에 아웃소싱 합니다.


선택한 텍스트 편집기를 사용하여 lib 폴더 내에 새 클래스를 작성하십시오.


vim lib/CliPrinter.php


다음 클래스는 세 가지 공개 메소드를 정의합니다. 메시지를 출력하는 기본 출력 메소드; 새로운 라인을 인쇄하는 새로운 라인 방법; 텍스트를 강조하기 위해 이 두 가지를 결합하여 새 줄로 감싸는 표시 방법이 있습니다. 더 많은 서식 옵션을 포함하도록 이 클래스를 나중에 확장 할 것입니다.


<?php

namespace Minicli;

class CliPrinter
{
    public function out($message)
    {
        echo $message;
    }

    public function newline()
    {
        $this->out("\n");
    }

    public function display($message)
    {
        $this->newline();
        $this->out($message);
        $this->newline();
        $this->newline();
    }
}


이제 CliPrinter 도우미 클래스를 사용하도록 App 클래스를 업데이트하겠습니다. CliPrinter 객체를 참조 할 $ printer라는 속성을 만듭니다. 개체는 앱 생성자 메서드에서 생성됩니다. 그런 다음 getPrinter 메소드를 작성하고 runCommand 메소드에서 이를 사용하여 echo를 직접 사용하는 대신 메시지를 표시합니다.


<?php

namespace Minicli;

class App
{
    protected $printer;

    public function __construct()
    {
        $this->printer = new CliPrinter();
    }

    public function getPrinter()
    {
        return $this->printer;
    }

    public function runCommand($argv)
    {
        $name = "World";
        if (isset($argv[1])) {
            $name = $argv[1];
        }

        $this->getPrinter()->display("Hello $name!!!");
    }
}

이제 다음을 사용하여 애플리케이션을 다시 실행하십시오.


./minicli your_name


메시지를 둘러싼 줄 바꿈과 같이 다음과 같이 출력 되어야 합니다.


Hello your_name!!!


다음 단계에서는 명령 로직을 App 클래스 외부로 이동하여 필요할 때마다 새 명령을 쉽게 포함 시킬 수 있습니다.


4. 명령 레지스트리 작성 


이제 일반적인 runCommand 메소드와 Command Registry를 통해 여러 명령을 처리하기 위해 App 클래스를 리팩터링 합니다. 일반적으로 인기 있는 PHP 웹 프레임 워크에서 경로가 정의 된 것처럼 새로운 명령이 등록됩니다.


업데이트 된 App 클래스는 이제 command_registry라는 새로운 속성 인 배열을 포함합니다. registerCommand 메소드는 이 변수를 사용하여 애플리케이션 명령을 이름으로 식별 되는 익명 함수로 저장합니다.


runCommand 메소드는 $argv [1]이 등록 된 명령 이름으로 설정되어 있는지 확인합니다. 명령이 설정되어 있지 않으면 기본적으로 도움말 명령을 실행하려고 시도합니다. 유효한 명령이 없으면 오류 메시지가 인쇄됩니다.


업데이트 된 App.php 클래스가 이러한 변경 후에 어떻게 보이는지 입니다. App.php 파일의 현재 내용을 다음 코드로 바꿉니다 :


<?php

namespace Minicli;

class App
{
    protected $printer;

    protected $registry = [];

    public function __construct()
    {
        $this->printer = new CliPrinter();
    }

    public function getPrinter()
    {
        return $this->printer;
    }

    public function registerCommand($name, $callable)
    {
        $this->registry[$name] = $callable;
    }

    public function getCommand($command)
    {
        return isset($this->registry[$command]) ? $this->registry[$command] : null;
    }

    public function runCommand(array $argv = [])
    {
        $command_name = "help";

        if (isset($argv[1])) {
            $command_name = $argv[1];
        }

        $command = $this->getCommand($command_name);
        if ($command === null) {
            $this->getPrinter()->display("ERROR: Command \"$command_name\" not found.");
            exit;
        }

        call_user_func($command, $argv);
    }
}


다음으로 minicli 스크립트를 업데이트하고 hello와 help라는 두 가지 명령을 등록합니다. 새로 만든 registerCommand 메소드를 사용하여 App 객체 내에 익명 함수로 등록됩니다.


업데이트 된 minicli 스크립트를 복사하고 파일을 업데이트하십시오.


#!/usr/bin/php
<?php

if (php_sapi_name() !== 'cli') {
    exit;
}

require __DIR__ . '/vendor/autoload.php';

use Minicli\App;

$app = new App();

$app->registerCommand('hello', function (array $argv) use ($app) {
    $name = isset ($argv[2]) ? $argv[2] : "World";
    $app->getPrinter()->display("Hello $name!!!");
});

$app->registerCommand('help', function (array $argv) use ($app) {
    $app->getPrinter()->display("usage: minicli hello [ your-name ]");
});

$app->runCommand($argv);

이제 응용 프로그램에는 help와 hello라는 두 가지 작업 명령이 있습니다. 테스트하려면 다음을 실행하십시오.


./minicli help


인쇄됩니다 :


usage: minicli hello [ your-name ]


이제 hello 명령을 다음과 같이 테스트하십시오.'


./minicli hello your_name
Hello your_name!!!

이제 더 많은 명령과 기능을 구현하기 위한 기본 역할을 하는 미니멀리스트 구조를 사용하는 작동 중인 CLI 앱이 있습니다.


이 시점에서 디렉토리 구조는 다음과 같습니다.


.
├── app
├── lib
│   ├── App.php
│   └── CliPrinter.php
├── vendor
│   ├── composer
│   └── autoload.php
├── composer.json
└── minicli


이 시리즈의 다음 부분에서는 명령 논리를 응용 프로그램 별 네임 스페이스 내의 전용 클래스로 이동하여 minicli를 명령 컨트롤러를 사용하도록 리팩터링 합니다. 다음에 또 만나요!


이 튜토리얼에서 사용 된 모든 파일은 여기에서 찾을 수 있습니다 : erikaheidi minicli : v0.1.0