# 爆速軽量フレームワーク codeigniter PHP 開発

仕事の関係で laravel も使ったことありますが、最初はあれこれ設定に悩まれましたが、1 年くらい使ったら laravel の便利さ強さがわかりました。
codeigniter になれたせいかわからないけど、やっぱり codeigniter のクエリビルダーの使いやすさはわすれられなくて、twig テンプレエンジンと組み合わせると最強最高のコーディング体験になります。久々 codeigniter やってなかったこともあり、メモもいままでなかったので、自由研究しながら、1 年ぶりに codeigniter でプロジェクト立ち上げです。
laravel との比べはしないけど、主に codeigniter の便利機能と忘れがちのところメモります。

# codeigniter はいつから PHP8 サポート?

2020 年 11 月 26 日に PHP8 リリースされましたが、codeigniter は php8 サポートするでしょうか?
PHP8 は 2 倍以上の速くなるそうですが、従来バージョンとの互換性が問題ですね。
PHP8 の新機能で関数にマルチタイプを追加すると、PHP 7.x との下位互換性が失われし、codeigniter のメリットの一つとして幅広いバージョンの PHP 対応していることもなくなります。
codeigniter のフォーラムに質問したものがいますが、==「近い将来追加される可能性はほとんどない」==そうです。
確かにバージョンの互換性は大事ですが、新バージョンの言語にいつか対応しないとどうなるでしょうか少し不安があります。これから laravel とかのフレームワークと比較する時も選択に影響するかもしれません。
codeigniter ファイト!

# htaccess 設定して url にある index.php 削除

.htaccess ファイル

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

# モデル query builder

laravel のクエリビルダーも使ったことありますが、やはり codeigniter のほうが抜群に使いやすい

codeigniter 3.2 公式 query builder 編 (opens new window)

# insert した行の id を返却 insert_id

insert_id は laravel の insertGetId() のように codeigniter model に insert した行の id 取得可能

User_model.php




 


    public function insertRow($data)
    {
        $this->db->table($this->table)->insert($data);
        return $this->db->insert_id();
    }

# コンパイル sql 文出力 get_compiled_select

get_compiled_select は laravel の toSql()のように codeigniter model にコンパイルしたクエリ sql 文を返却

echo $this->db->select('title, content, date')->get_compiled_select();
// 出力: SELECT title, content, date FROM mytable

# where の4つの使い方

  • key,value 個別指定
$this->db->where('column_key', $value);
  • イコールじゃないパターン
$this->db->where('column_key !=', $value);
$this->db->where('id <', $id);
  • 連想配列指定
$this->db->where(['id' => $id]);
  • string 生の文字列渡す

ちょっと違和感感じるけど、文字列も配列もそのままwhereに掘り込んだら動いてくれる、PHP らしいプログラム!

$where = "name='Joe' AND status='boss' OR status='active'";
$this->db->where($where);

// $this->db->where() にはオプションで第3の引数を渡すこともできます。
// FALSE を渡した場合、CodeIgniter はフィールド名やテーブル名を守りません。
$this->db->where('MATCH (field) AGAINST ("value")', NULL, FALSE);

# get_where

get_where(テーブル名,where 配列,limit,offset)

// get_where(テーブル名,where 配列,limit,offset)
$this->db->get_where('table_name', ['id' => $id], $limit, $offset);

// 以下のものと同じ
$this->db->where(['id' => $id])
         ->limit($limit)
         ->offset($offset)
         ->get('table_name);

# dotenv 使う

laravel 使い慣れてたら、.envは便利でいいですね。codeigniter もデフォルトで入れるべきだと思うくらい。
調べてたら composer に dotenv があったので、codeigniter に dotenv 入れてみる

# 方法 1 vlucas/phpdotenv

  • 環境:CodeIgniter3
  • ライブラリ: vlucas/phpdotenv
  • php: ^5.5.9 || ^7.0

codeigniter の hook 機能使って、pre_system システム読み込む前に env の読み込んで初期設定することで、グローバルに env 内容展開。

# vlucas/phpdotenv インストール

composer require vlucas/phpdotenv

# config ファイル設定

config/config.php hook 有効化

// composer autoload有効化
$config['composer_autoload'] = TRUE;

// hooks有効化
$config['enable_hooks'] = TRUE;

# hooks ファイル編集

codeigniter/config/hooks.php






 












<?php
defined('BASEPATH') or exit('No direct script access allowed');

$hook['pre_system'] = function () {
    try {
        $dotenv = Dotenv\Dotenv::createImmutable(APPPATH . '../');  // 自分の環境に合わせてenvファイルのパス設定
        $dotenv->load();
    } catch (Exception $e) {
        //
    }

    function env(string $key, $default = null)
    {
        $value = $_ENV[$key];
        return ($value) ? $value : $default;
    }
};

ポイント:パス設定

createImmutable で.env ディレクトリまで指定

.env

DB_HOST=localhost
DB_USER=root
DB_PASS=
DB_NAME=test2

config/database.php

$db['default'] = array(
    'dsn' => '',
    'hostname' => env('DB_HOST'),
    'username' => env('DB_USER'),
    'password' => env('DB_PASS'),
    'database' => env('DB_NAME'),

完了!任意の場所からenv()使えます。

config/config.php の中で使えない

どこでも env 可能だと思って config/config.php の中は設定したらエラーになった

config.php の中で base_url 設定も env から呼び込めばいいなあと思って設定して見ました

$config['base_url'] = 'http://' . env('BASE_URL');

# Call to undefined function env()エラー

Fatal error: Uncaught Error: Call to undefined function env() in C:\xampp\htdocs\hclo\application\config\config.php:26 Stack trace: #0 C:\xampp\htdocs\hclo\system\core\Common.php(249): require() #1 C:\xampp\htdocs\hclo\system\core\Common.php(300): get_config() #2 C:\xampp\htdocs\hclo\system\core\Common.php(171): config_item('subclass_prefix') #3 C:\xampp\htdocs\hclo\system\core\Common.php(652): load_class('Exceptions', 'core') #4 [internal function]: _exception_handler(Object(Error)) #5 {main} thrown in C:\xampp\htdocs\hclo\application\config\config.php on line 26

Fatal error: Uncaught Error: Call to undefined function env() in C:\xampp\htdocs\hclo\application\config\config.php:26 Stack trace: #0 C:\xampp\htdocs\hclo\system\core\Common.php(249): require() #1 C:\xampp\htdocs\hclo\system\core\Common.php(300): get_config() #2 C:\xampp\htdocs\hclo\system\core\Common.php(171): config_item('subclass_prefix') #3 C:\xampp\htdocs\hclo\system\core\Common.php(617): load_class('Exceptions', 'core') #4 C:\xampp\htdocs\hclo\system\core\Common.php(689): _error_handler(1, 'Uncaught Error:...', 'C:\\xampp\\htdocs...', 26) #5 [internal function]: _shutdown_handler() #6 {main} thrown in C:\xampp\htdocs\hclo\application\config\config.php on line 26

結論: config 内に env 使うことができない

SERVER の HTTP_HOST 指定しました。

$config['base_url'] = $_SERVER['HTTP_HOST'];

# 方法 2 symfony/dotenv

  • 環境:CodeIgniter3
  • ライブラリ: symfony/dotenv
  • php: ^7.2.5

symfony dotenv は、シンフォニーチームが開発した php システムが利用できる.env ファイル読み込むためのコンポーネントです。
MY_Controller で実装すると、controller 読み込んでからでないと env 設定使えないので、hook の pre_system 使うべき
vlucas/phpdotenv もいけるけど、個人的に symfony が好きなシンフォニー派なので、symfony/dotenv 使います。愛用 twig もシンフォニー製
ただ、php 7.2 からはちょっとバージョン高くない?

env function 作成しておくと便利に使える

# symfony/dotenv インストールと初期設定

上記の vlucas/phpdotenv と一緒で割愛

# hooks 設定

codeigniter/config/hooks.php








 











<?php
defined('BASEPATH') or exit('No direct script access allowed');
use Symfony\Component\Dotenv\Dotenv;

$hook['pre_system'] = function () {
    try {
        $dotenv = new Dotenv();
        $dotenv->load(APPPATH . '../.env'); // 自分の環境に合わせてenvファイルのパス設定
    } catch (Exception $e) {
        //
    }

    function env(string $key, $default = null)
    {
        $value = $_ENV[$key];
        return $value ?? $default;
    }
};

ポイント

.env ファイルまでパス設定する必要がある

.env

DB_HOST=localhost
DB_USER=root
DB_PASS=
DB_NAME=test2

config/database.php

$db['default'] = array(
    'dsn' => '',
    'hostname' => env('DB_HOST'),
    'username' => env('DB_USER'),
    'password' => env('DB_PASS'),
    'database' => env('DB_NAME'),

完了!任意の場所からenv()使えます。

# Message: Class 'Symfony\Component\Dotenv\Dotenv' not found エラー発生




 



An uncaught Exception was encountered
Type: Error

Message: Class 'Symfony\Component\Dotenv\Dotenv' not found

Filename: /Users/t/Documents/www.com/application/config/hooks.php

windows では動いてくれてたけど、mac では動かない!あるあるパターンですけど、dotenv not found って composer install 忘れたかなあと思ったりしますが、install コマンド走らせても特に解消しない
composer update かけてみたら原因がわかりました。

 












$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - symfony/dotenv v5.0.4 requires php ^7.2.5 -> your PHP version (7.1.23) does not satisfy that requirement.
    - symfony/dotenv v5.0.3 requires php ^7.2.5 -> your PHP version (7.1.23) does not satisfy that requirement.
    - symfony/dotenv v5.0.2 requires php ^7.2.5 -> your PHP version (7.1.23) does not satisfy that requirement.
    - symfony/dotenv v5.0.1 requires php ^7.2.5 -> your PHP version (7.1.23) does not satisfy that requirement.
    - symfony/dotenv v5.0.0 requires php ^7.2.5 -> your PHP version (7.1.23) does not satisfy that requirement.
    - Installation request for symfony/dotenv ^5.0 -> satisfiable by symfony/dotenv[v5.0.0, v5.0.1, v5.0.2, v5.0.3, v5.0.4].

原因はドキュメントに書いてあります。requires php: ^7.2.5

うん、ドキュメントはちゃんと読むべき!

比べてどうする ちなみに、vlucas/phpdotenv の php 環境要件はずっと低いけど、php: ^5.5.9 || ^7.0で動きます。
vlucas/phpdotenv のほうが人気の理由がこれにあるかもしれません。

# ライフサイクル

codeigniter のライフサイクル知りたかったけど、調べても見つからなくて、そういえば laravel はどうかなあと laravel のライフサイクルを調べました。

laravel ライフサイクル

  1. public/index.php
  2. Http/Console カーネル($bootstrappers middleware)
    リクエスト実行前$bootstrappers 配列に定義しているサービスプロバイダ,env,config,Facadeとかがここでこ見込まれる。
  3. Router
  4. Controller
  5. View

laravel $bootstrappers

vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php

protected $bootstrappers = [
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
    \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
    \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
    \Illuminate\Foundation\Bootstrap\BootProviders::class,
];

laravel config 読み込み LoadConfiguration

vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php

public function bootstrap(Application $app)
{
     $items = [];

     if (file_exists($cached = $app->getCachedConfigPath())) {
         $items = require $cached;

         $loadedFromCache = true;
     }

     $app->instance('config', $config = new Repository($items));

     if (! isset($loadedFromCache)) {
         $this->loadConfigurationFiles($app, $config);
     }

     $app->detectEnvironment(function () use ($config) {
         return $config->get('app.env', 'production');
     });

     date_default_timezone_set($config->get('app.timezone', 'UTC'));

     mb_internal_encoding('UTF-8');
}

# codeigniter のフック

フレームワークコアの拡張として紹介されていますが、非常にわかりやすくて使いやすい!これですぐに middleware やアクセス トラッキング、IP 制限など作れてしまう!

# フック有効化

application/config/config.phpファイル編集でフックの有効化 $config['enable_hooks'] = TRUE;

# フック定義

application/config/hooks.php

<?php
defined('BASEPATH') or exit('No direct script access allowed');
use Symfony\Component\Dotenv\Dotenv;

$hook['pre_controller'] = array(
        'class'    => 'MyClass',
        'function' => 'Myfunction',
        'filename' => 'Myclass.php',
        'filepath' => 'hooks',
        'params'   => array('beer', 'wine', 'snacks')
);

$hook['pre_system'] = function () {
    try {
        $dotenv = new Dotenv();
        $dotenv->load(APPPATH . '../.env');
    } catch (Exception $e) {
        //
    }

    function env(string $key, $default = null)
    {
        $value = $_ENV[$key];
        return $value ?? $default;
    }
};

# フックポイント

  • pre_system

    システム実行中の非常に早い段階で呼び出されます。ベンチマーククラスと フッククラスだけがこの時点でロードされています。ルーティングや 他のプロセスは実行されていません。

  • pre_controller

    いずれかのコントローラが呼び出される直前に呼び出されます。 すべての基本クラス、ルーティング、およびセキュリティチェックは実行済みです。

  • post_controller_constructor

    コントローラがインスタンス化された直後に、 しかしメソッド呼び出しをする前に呼び出されます。

  • post_controller

    コントローラの実行が完全に終わった直後に呼び出されます。

  • display_override

    _display() メソッドをオーバーライドします。システム実行の最後で ウェブブラウザに確定ページを送信するために使用されるものです。これにより 独自の方法による表示が可能になります。 CI スーパーオブジェクトへの参照が $this->CI =& get_instance() により必要となること、 そして確定データは $this->CI->output->get_output() を呼び出すことによって利用できるようになることを覚えておいてください。

  • cache_override

    _display_cache() メソッドのかわりに独自のメソッドを呼び出すことができます。これにより、 独自のキャッシュ表示機構を使用できるようになります。

  • post_system

    最終的にレンダリングされるページがブラウザに送られた後、 つまりブラウザに確定データが送信されシステム実行が終了する時に 呼び出されます。

ここでみる codeigniter のライフサイクル

  1. ベンチマーククラス & フッククラス
  2. config 系設定ファイル
  3. controller & model
  4. view など display メソッド

参考:フック――フレームワークコアの拡張 (opens new window)

# twig テンプレートエンジン実装

PHP テンプレートエンジン twig 3 インストール

  1. composer install してから MY_Controller の設定

  2. application/config/config.php ファイル composer autoload 設定
    $config['composer_autoload'] = true; composer_autoload を true に変更

  3. application/core/MY_Controller.php ファイル設定

# twig2 初期設定

<?php
class MY_Controller extends CI_Controller
{
    protected $twig;

    public function __construct()
    {
        parent::__construct();

        $loader = new Twig_Loader_Filesystem('./application/views');
        $this->twig = new Twig_Environment($loader);
        // option設定
        // $this->twig = new Twig_Environment($loader, array('cache' => APPPATH.'/cache/twig', 'debug' => true));

        // twig global 設定
        // if (!empty($this->session->is_login)) {
        //     $this->twig->addGlobal('is_login', $this->session->is_login);
        // }

        // debug
        // $this->output->enable_profiler('TRUE');
    }
}

# twig3 初期設定

<?php
class MY_Controller extends CI_Controller
{
    protected $twig;

    public function __construct()
    {
        parent::__construct();

        // Twig 初期化
        $loader = new \Twig\Loader\FilesystemLoader('../application/views');
        $this->twig = new \Twig\Environment($loader, [
            // 'cache' => '/path/to/compilation_cache',
        ]);
    }
}

# Class 'Twig_Loader_Filesystem' not found エラー対応

An uncaught Exception was encountered
Type: Error

Message: Class 'Twig_Loader_Filesystem' not found

twig loader 見つからないと言ってます。twig3 初期設定と従来 twig2 の初期設定と違う ので twig2 から twig3 にアップしたらエラー出ます。

# The "./application/views" directory does not exist エラー対応

An uncaught Exception was encountered
Type: Twig\Error\LoaderError

Message: The "./application/views" directory does not exist ("\x\public_html./application/views").

public index.php 対してのパス設定ミスが原因

$loader = new \Twig\Loader\FilesystemLoader('../application/views');

環境によりますが、MY_Controller.php の\Twig\Loader\FilesystemLoader を../application/viewsに設定したり、./application/viewsに設定したりする必要があります。

# Call to a member function display() on null エラー対応

An uncaught Exception was encountered
Type: Error

Message: Call to a member function display() on null

display function が見つからないことが原因 $this->twig にセットしてない可能性?

# Call to a member function insert() on null エラー対応

An uncaught Exception was encountered
Type: Error

Message: Call to a member function insert() on null

model insert 呼び込みできないエラー

  • $this->load->model('model_name')忘れているでは?

  • ライブラリ自動読み込みしてないでは?

config/autoload.php

$autoload['libraries'] = array('database');

# Invalid argument supplied for foreach() エラー対応

A PHP Error was encountered
Severity: Warning

Message: Invalid argument supplied for foreach()

foreach()で回す時に出てくるエラーで、foreach が使えるのは配列とオブジェクトだけって怒られています

回す前に(array)配列変換してあげることで問題解決

foreach((array) $items as $i){
    echo $i;
}
2020-01-30
  • php
  • codeigniter

関連記事

Laravel メンテナンスモード
Laravel でカテゴリー作成 テーブル構築と再帰クエリ
Laravel を API サーバーとしての初期設定
Laravel リクエストログ出力
Laravel 429 Too Many Requests
Laravel Email バリデーションについて
Laravel Sanctum 使って API トークン JWT 認証と SPA 認証
Laravel logger でエラーログを chatwork に自動送信
php CSV データ取得は fgetcsv 使う
Laravel tinker 使って DB データベース接続とコマンド
Laravel Test についてのメモ
Laravel Log の基本設定&使い方
Exception: Class 'ZipArchive' not found
Laravel Sail で Docker 環境構築
PHP 文字列長さ・文字列の幅を取得方法
Codeigniter 画像アップロードとリサイズ
Laravel Lumen Faker 日本語設定
laravel method の基本 get post put options
Laravel schedule 設定
Class 'Imagick' not found Error
Laravel eloquent model の規約
PHP mbconvertkana 全角半角英数カナ変換
Codeigniter APPPATH BASEPATH FCPATH 各種パスと URL 取得
Laravel timestamp() auto update 有効化無効化
Lumen8 で JWT ユーザー認証
Laravel toSql パラメータ付きで出力
Lumen8 で API 開発
php Exception エラーキャッチでメール送信
Smarty HTTP URL 取得できるサーバー関数
Laravel blade foreach loop と current url
laravel session を制する
PHP empty isset is_null の違い
PHP 8 リリース新機能と変更
FlattenException deprecated
php.ini 初期設定のいろいろ
Laravel 5.1 から 8.1 にバージョンアップ
PHP 7.4 にアップグレードして使えなくなる機能
開発時によく使うゼロ埋めパディング作業まとめ
解決!phpMyAdmin テーブル構造の内容が表示されない問題
Composer コマンドとオプション
Lumen と Laravel 違い比較
HTML から PDF に変換 PHP ライブラリ mPDF の設定
twig 3 人気 PHP テンプレートエンジンがバージョンアップ
Laravel Error についてのメモ
laravel に vuejs 使うための初期設定
php curl 使って クリックなしで POST 送信
allowurlinclude の設定で ftp_connect()エラー
Carbon で php date 日付の日数・月数差を計算
codeigniter email ライブラリでメール送信 日本語対応
nuxtjs と codeigniter で jwt システム構築
正規表現一覧 よく使う検索・置換のパターン
Apache 初期設定メモ
開発におけるコーディングルール・規約