composerを使ったautoload

Composerはパッケージ管理以外にオートロードという機能を合わせ持ち、require文を使用しなくてもクラスファイルを読み込むことができる

### require文の使い方
Userクラスを作成する

src/User.php

class User{

	protected $name;

	public function __construct($name){
		$this->name = $name;
	}

	public function get_user_name(){
		return $this->name;
	}
}

index.php

require('src/User.php');

$user  = new User('taro');

var_dump($user->get_user_name());

composer.json

{
	"autoload": {
		"psr-4": {
			"Test\\": "src"
		}
	}
}

php composer.phar dump-autoload
/vendor/composer/autoload_psr4.php

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'Test\\' => array($baseDir . '/src'),
);
namespace Test;

class User{

	protected $name;

	public function __construct($name){
		$this->name = $name;
	}

	public function get_user_name(){
		return $this->name;
	}
}

なるほど、requireではなく、composerでautoloadできることはわかった。

PHP PSR-4とは

PSRとはPHP Standard Recommendationsのことで、PHP-FIG(PHP Interop Group)が昨制定しているコーディング規約のこと。PRSにはいくつか種類がある。
PSR-4はAutoloader
ファイルパスからクラスをオートロードするための規約
PSR-0という削除予定の規約もある
\(\)*\

どのパスにどのクラスを配置するのか仕様を決めたいというのが根にある

psr-0とpsr-4があるってことはわかったが、autoloadの仕組みがよくわからん。require_onceとは違うのね。。。

PHPと名前空間

namespaceは名前空間と呼ばれ、項目をカプセル化するときに使用する
通常、同じファイルに同じクラスや関数名、定数めいが存在することはできないが、名前空間を使用することにより、関連するクラスやインターフェイス、関数、定数などをグループ化することが可能
名前が衝突することを防ぐことができる
namespaceは以下のように記述する

namespace 名前空間名;

ソースコードの一番先頭で宣言する必要があり、namespaceの前にHTMLを記述するとエラーになる

sample1.php

namespace name1;
function getName(){
	return "fruit";
}

namespace name2;
function getName(){
	return "ore";
}

sample2.php

//phpファイルを読み込む
require_once 'sample1.php';
 
//関数の呼出し
echo name1\getName();
echo name2\getName();

$ php sample2.php
fruitore

namespaceを宣言すると、その後に記述した関数はその名前空間の関数に属する
名前空間\関数名とすれば同一の関数を呼び出すことが可能になる

波括弧で指定したい範囲を囲むこともできる

namespace name1 {
	function getName(){
		return "fruit";
	}
}

namespace name2{
	function getName(){
		return "ore";
	}
}

波括弧で囲むと、名前空間の範囲外で命令文を記述することができなくなってしまう

namespace name1 {
	function getName(){
		return "fruit";
	}
}


namespace name2{
	function getName(){
		return "ore";
	}
}

echo "Hello World!";

### useの使い方
useとは名前空間の拡張機能で、外部のエイリアスやその一部を参照したり、クラス・関数・定数などをインポートするときに使用する

namespace asia\japan\tokyo\shibuya;

function getName(){
	return "shibuya";
}


namespace asia\japan\tokyo\minato;

function getName(){
	return "minato";
}

namespace asia\japan\tokyo\shinagawa;

function getName(){
	return "shinagawa";
}
[_code]


require_once "sample1.php";

use asia\japan\tokyo as name;

echo name\shibuya\getName();
echo name\minato\getName();

名前空間のnamespaceとuseはなんとなくわかったが、composer.jsonのpsr-4, psr-0がイマイチよくわからん。。

packageを自作してcomposer.jsonで動かそう

### ライブラリ側
$ tree
.
├── composer.json
├── src
│   └── Muuu
│   └── Uuuu.php
└── test

/src/Muuu/Uuuu.php

class Dog {

	private $name;

	public function __construct($name){
		$this->name = $name;
	} 

	public function getName(){
		return $this->name . "さん!";
	}
}

$ git init
$ git add .
$ git commit -m “first commit”
$ git remote add origin
$ git push -u origin master

### プロジェクト側
composer.json

{
    "name": "library/test",
    "description": "Composer sample project",
    "authors": [
    	{
    		"name": "hpscript",
    		"email": "hpscript@gmail.com"
    	}
    ],
    "type": "project",
    "minimum-stability": "dev",
    "require": {
    	"nuuu/muuu": "*"
    },
    "autoload": {
        "psr-4": {"App\\": "src/"}
    },
    "repositories": {
    	"nuuu/muuu": {
    		"type": "vcs",
    		"url": "https://github.com/hpscript/package.git"
    	}
    }
}
require_once "./vendor/autoload.php";
use App\Muuu\Uuuu;

$dog = new Uuuu::Dog("hoge");
$dog_name = $dog->getName();
echo $dog_name;

名前空間とclassの概念はよくわからん。。。

composer管理の考え方

・パッケージ作成
・composerで管理
・別プロジェクトで使用
・gitのプライベートリポジトリでパッケージは管理

パッケージのディレクトリがプロジェクト
基本的にはPackagist(https://packagist.org/)で管理されている
公開したくないパッケージはprivate リポジトリからの読み取りも可能
タグでバージョン管理ができる

### パッケージのディレクトリ構成

<package>/
    .git/
    .gitignore
    composer.json
    src/
        <namspace>/
            <class>.php
    tests/
        <namspace>/
            <class>Test.php

### パッケージを使う側のプロジェクト

<root>/
    composer.json
    composer.lock
    <vendor>/
        autoload.php
        <composer>/
        <any packages>/
        ...

### composer.jsonの書式
読み込む側のcomposer.json

{
    "name": "<vendor>/<project_name>",
    "description": "Composer sample project",
    "authors": [
    	{
    		"name": "<author>",
    		"email": "<mail@gmail.com>"
    	}
    ],
    "require": {
    	"nuuu/muuu": "^1.0"
    },
    "autoload": {
    	"psr-4": {"<NamespacePrefix>\\": "src/"}
    },
    "repositories": [
    	{
    		"type": "vcs",
    		"url": "ssh://user@loacalhost/var/git/repos/nuu_muu.git"
    	}

    ]
}

呼び出し

<?php

require_once "./vendor/autoload.php";
use Nuuu\Muuu\Uuuu;

Uuuu::sayHello();

なるほど、テストしてみないとわからんな。

openapi-generatorを利用

$ npm init
$ npm install –include=dev openapi-generator-cli
npm ERR! code E404
npm ERR! 404 Not Found – GET https://registry.npmjs.org/openapi-generator-cli – Not found
npm ERR! 404
npm ERR! 404 ‘openapi-generator-cli@*’ is not in this registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.

npm ERR! A complete log of this run can be found in:
あれ? イマイチよくわからない

PHPの多重起動防止の書き方

実行時にロックファイルを作成して、実行が終わったら削除する

<?php

$lock_file = "./test.lock";

if (!file_exists($lock_file)){
	$fp = fopen($lock_file, "w+");

	for($i = 0; $i < 50; $i++){
		sleep(1);
	}

	fclose($fp);
	unlink($lock_file);
} else {
	echo "Already running!!";
}

ただし、実行中にエラーがあることがあるので、排他ロックをするという方法もある。

$file = fopen("test.lock", "w+");

if (flock($file, LOCK_EX + LOCK_NB)){
	
	for($i = 0; $i < 50; $i++){
		sleep(1);
	}

	flock($file, LOCK_UN);
} else {
	echo "Already running!!";
}

LOCK_EX: 排他的なロック。このフラグ単体だけの場合、他プロセスがアクセスした時に解除されるまでブロックするという挙動になる

PostgreSQLにPDOでphpから接続する

### 接続

$dsn = "pgsql:dbname=testdb host=localhost port=5432";
$user = "user1";
$password = "password";

try {
	$dbh = new PDO($dsn, $user, $password);
	print('接続に成功しました');
} catch(PDOException $e){
	print("Error:".$e->getMessage());
	die();
}

### sql実行

$dsn = "pgsql:dbname=testdb host=localhost port=5432";
$user = "user1";
$password = "password";

try {
	$dbh = new PDO($dsn, $user, $password);
	print('接続に成功しました<br>');

	$sql = 'select * from department';
	foreach($dbh->query($sql) as $row){
		print($row['department_code'].":");
		print($row['department_name'].",");

	}
} catch(PDOException $e){
	print("Error:".$e->getMessage());
	die();
}

$ php index.php
接続に成功しました
a:営業部,b:総務部,d:経理部,e:人事部,f:物流部,

PDOはmysqlと然程変わらないですな

php_valueの使い方

Apacheのモジュールとして使用しているPHPの設定を.htaccessで変更する場合、php_valueとphp_flagで設定する。
php_flagは論理値(true, false)を設定し、php_valueはそれ以外の値を設定する
php_value, php_flag共にPHP_INI_ALLまたはPHP_INI_PERDIRの設定オプションに対して利用できる
セットされている値をクリアしたい場合、php_valueにnoneを値として設定することでクリアできる

よく設定する項目

php_value memory_limit 128M
php_value memory_limit -1
php_value post_max_size 64M
php_value upload_max_filesize 10M
php_value max_execution_time 60
php_value mbstring.internal_encoding UTF-8
php_value mbstring.detect_order UTF-8, SJIS-win, SJIS, eucJP-win, EUC-JP, JIS, ASCII
php_value mbstring.language Japanese
php_value output_buffering off
php_value max_input_vars 2000
php_flag session.cookie_secure On
php_flag session.cookie_httponly On
ini_set("session.cookie_path", "/path/");
php_value date.timezone "Asia/Tokyo"
php_flag short_open_tag On
php_flag display_errors On
php_value error_reporting 6135 // all error
php_flag log_errors On
php_value error_log "./logs/error.log"

### テスト
/etc/apache2/apache2.conf

<Directory /var/www/>
	Options Indexes FollowSymLinks
	AllowOverride None
	Require all granted
</Directory>

.htaccess

php_flag log_errors On
php_value error_log /var/www/html/error.log

$ sudo systemctl restart apache2

error.log
[31-Dec-2022 03:49:59 UTC] PHP Parse error: syntax error, unexpected end of file, expecting ‘;’ or ‘,’ in /var/www/html/app.php on line 5
[31-Dec-2022 03:50:00 UTC] PHP Parse error: syntax error, unexpected end of file, expecting ‘;’ or ‘,’ in /var/www/html/app.php on line 5

OK!

PHPの正規表現 ○を含む AND △を含む

$str = "0aZ";
if(preg_match("/^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=\S+$).*$/", $str)){
	echo "マッチします。";
} else {
	echo "マッチしません。";
}

\S+$は半角を含まないという意味かな
なるほど、理解に時間がかかったわ