2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【実務未経験 歓迎】PHPで「Hello World」してみよう [異世界転生(転職)・なろう]

Last updated at Posted at 2024-07-29

はじめに

どうもはじめまして、異世転生者のジツム・ミケイケンと申します。

ある日交差点で車に轢かれてしまった俺はエスイーエス?というよくわからない世界に飛ばされてしまった。
右も左もわからない俺だが、ここでの生活の為にHello Worldくらいは書けるようになっておこうと思う。

本記事の成果物 (コピペ用)

短い時間で解決したい方に配慮し、本記事で作成するプログラムの成果物を先に開示しておきます。 (省エネ)

main.php
<?php

hello_world("Да не люблю я Кудзэ-куна!");

本編

ここからは、上記コードを実行できるように手順を書いていきます。

記事をスクロールしながらコピペさえすれば動作するよう書いていく為、手元で動かしたい方はやってみて下さい。

あと、最近筆者が

時々ボソッとロシア語でデレる隣のアーリャさん

にハマってしまった影響でサンプルコードにも影響が出ていますがご容赦下さい。

記事を読んでいくと前述のmain.phpのロシア語で何を言っているかが判明します。
(え?どうでもいいって?)

環境

  • M1 Mac
  • Docker Desktop
    • OS: debian 12

※これじゃないと動かないというよりも、筆者はこれで動きました的なやつです。

作成予定のファイル構成

ふんわりと、こんな感じのファイル作成するんだな〜と思いながら読み飛ばして下さい。

.
├── Dockerfile
├── Makefile
├── alya.cpp
├── alya.ini
└── main.php

まずはDockerをInstallしましょう

以下のリンクからDockerをダウンロードできます。
環境によってはDockerは不要ですが、筆者はホストマシンでうまく動かなかったので利用しています。

DockerとはMacの中で別の異世界を作るようなものであるとイメージして下さい。

実行環境の立ち上げ

PHPのinstallが面倒くさいので、もともとPHPが入っているDocker imageを利用します。

Dcokerfile
FROM php:bookworm

WORKDIR /app

RUN alias gs='git status -s' ## 仮想環境の中で打つの辛いので

RUN apt update
RUN apt install -y git
RUN apt install -y vim ## lsp使えないのが辛い...
RUN apt install -y clang-format ## それでもformatはしたい
RUN git clone https://github.com/CopernicaMarketingSoftware/PHP-CPP.git /tmp/PHP-CPP
RUN cd /tmp/PHP-CPP && \
    make && \
    make install

解説

PHPにはhello_worldという関数は存在しない為、関数自体を自作をしています。

## 具体的にはここから下の行です。

RUN git clone https://github.com/CopernicaMarketingSoftware/PHP-CPP.git /tmp/PHP-CPP

急に出てきたリポジトリですが、紹介します。
CopernicaMarketingSoftware/PHP-CPPとはC++でPHP extensionがコンパイルできるOSSで、本記事はこちらのライブラリがあって成立しています。

Extensionを作成するには他にもPHP FFIなどいくつかの方法があります。

  • Zend Extension (ネイティブ実行)
  • PHP Extension (ネイティブ実行)
  • PHP FFI (ネイティブ+Zend VM実行)
  • PHP Library (Zend VM実行)

Dockerfile作成後コンテナを立ち上げていく

## hogeという名前のImage作成
docker build -t hoge .
## fooという名前のコンテナを立ち上げ
docker run -itd -v $PWD:/app --name foo hoge

仮想環境の中に入る方法

docker exec -it foo bash

作成した環境の確認

あまり重要じゃないですが、環境差異でエラーになった方向けです。

## アーキテクチャ
arch
> aarch64

## OS
cat /etc/os-release
> PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
> NAME="Debian GNU/Linux"
> VERSION_ID="12"
> VERSION="12 (bookworm)"
> VERSION_CODENAME=bookworm
> ID=debian
> HOME_URL="https://www.debian.org/"
> SUPPORT_URL="https://www.debian.org/support"
> BUG_REPORT_URL="https://bugs.debian.org/"

## PHP
php -v
> PHP 8.3.9 (cli) (built: Jul 23 2024 06:02:10) (NTS)
> Copyright (c) The PHP Group
> Zend Engine v4.3.9, Copyright (c) Zend Technologies

## C++
c++ -v
> Using built-in specs.
> COLLECT_GCC=c++
> COLLECT_LTO_WRAPPER=/usr/lib/gcc/aarch64-linux-gnu/12/lto-wrapper
> Target: aarch64-linux-gnu
> Thread model: posix
> Supported LTO compression algorithms: zlib zstd
> gcc version 12.2.0 (Debian 12.2.0-14)

コンパイルに必要なファイルを揃える

Makefile

公式ドキュメントにMakefileを作ってくれとあるので作成しちゃいます。

ファイルの中で変更可能箇所にコメントしてます。

Makefile
CPP             = g++
RM              = rm -f
CPP_FLAGS       = -Wall -c -I. -O2 -std=c++11

PHP_CONFIG      = $(shell which php-config)
LIBRARY_DIR		= $(shell ${PHP_CONFIG} --extension-dir)
PHP_CONFIG_DIR	= $(shell ${PHP_CONFIG} --ini-dir)

LD              = g++
LD_FLAGS        = -Wall -shared -O2
RESULT          = alya.so ## ここをお好みで変えても大丈夫

PHPINIFILE		= alya.ini ## ここをお好みで変えても大丈夫

SOURCES			= $(wildcard *.cpp)
OBJECTS         = $(SOURCES:%.cpp=%.o)

all:	${OBJECTS} ${RESULT}

${RESULT}: ${OBJECTS}
		${LD} ${LD_FLAGS} -o $@ ${OBJECTS} -lphpcpp

clean: ##
		${RM} *.obj *~* ${OBJECTS} ${RESULT}

${OBJECTS}:
		${CPP} ${CPP_FLAGS} -fpic -o $@ ${@:%.o=%.cpp}

## PHP Extension Dirへcp
install:
		cp -f ${RESULT} ${LIBRARY_DIR}/
		cp -f ${PHPINIFILE}	${PHP_CONFIG_DIR}/

## PHP Extension Dirからrm
uninstall:
		rm ${LIBRARY_DIR}/${RESULT}
		rm ${PHP_CONFIG_DIR}/${PHPINIFILE}

alya.ini (php.ini)

PHPがロードする為のconfigファイルの作成を行います。
PHPINIFILEで定義しているので、makeで読み込まれます。

alya.ini
; 時々ボソッとロシア語でデレる隣のアーリャさん
extension=alya.so

C++コード

以下のC++コードで、hello_world関数を定義しつつextern "C"でCからC++を利用可能にしています。

公式Docにもありますが拡張機能は必ずget_moduleシンボルを提供する必要があります。

PHP extensions must export a get_module symbol.

あ、あたし拡張機能の名称を「tun_dere(ツンデレ)」になんか、してないんだからね!! ///

alya.cpp
#include <iostream>
#include <phpcpp.h>

using namespace std;

Php::Value hello_world(Php::Parameters &params) {
    string v = params[0].stringValue();

    cout << v + " (久世君なんか好きじゃないもん)" << endl;

    return 0;
}

extern "C" {
PHPCPP_EXPORT void *get_module() {
    static Php::Extension extension("tun_dere", "1.0");

    extension.add<hello_world>("hello_world",
                               {
                                   Php::ByVal("string", Php::Type::String),
                               });

    return extension.module();
}
}

ファイルが揃ったのでビルドしていく

Build

書いたC++(C)コードをPHPで利用可能にするため、.soファイル(PHP拡張機能)を生成します。

make
> g++ -Wall -c -I. -O2 -std=c++11 -fpic -o alya.o alya.cpp
> g++ -Wall -shared -O2 -o alya.so alya.o -lphpcpp

-o alya.so alya.oとなっているので、soファイルが作成されていそうです。

/php/extensionsや/php/conf.dに各種ファイル設置

make install
> cp -f alya.so  /usr/local/lib/php/extensions/no-debug-non-zts-20230831/
> cp -f alya.ini 	/usr/local/etc/php/conf.d/

自作したPHP拡張機能がinstallされているか確認

php -m | grep -2 tun_dere
> standard
> tokenizer
> tun_dere ## <=== installされている! 
> xml
> xmlreader

おまけ (デバッグしたい場合)

make clean && make && make install

### 以下コマンドを打ったのと同じ
## make clean
## make
## make uninstall
## make install

さあ「Hello World」をしてみよう! (ついにタイトル回収)

main.phpというファイルを以下の内容で作成します。

main.php
<?php
## ※アーリャはロシア語でデレます
hello_world("Да не люблю я Кудзэ-куна!");

作成したファイルを実行してみます。

## PHP 実行
php main.php

実行結果

abc.png

本当は俺のこと好きなくせにってやつですね(^o^)♪ <= ちょっとキモい

まとめ

俺は無事に「ケイケンネンスウ・サンネンイジョウ」を手にして、異世界のんびりスローライフ生活を送れる日は来るのだろうか ...


次回予告: 受託開発国、闇の見積もり村編

※ 本記事はフィクションです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?