20191001のPHPに関する記事は9件です。

オブジェクト指向のクラスの書き方

オブジェクト指向とは?

プログラムという仮想の世界を、現実世界の実体(オブジェクト)に合わせて、プログラムを書いていく、という考え方のこと。
その考え方に基づいてプログラムを書いていくことで、保守性が高くなる。



例えばゲームに登場させるモンスターを30体用意しなきゃいけない、ということになったとき、
30体全部を一体ずつ作成するのは大変です。

オブジェクト指向で書かないとどうなる?

今学んでいるのがPHP言語なのでPHPで以下の説明コードを書いていきます。

一般的なゲームでは、

モンスターの名前、属性、見た目、HP、攻撃力、防御力

などなどが必要です。

それらを連想配列で用意していきます。

// モンスターたち格納用配列
$monsters = array();

$monsters[] = array(
   'name' => ‘ファイアーマン,
   attribute => ,
   'hp' => 100,
   'img' => 'monster01.png',
   'attack' => mt_rand(20, 40)
 ’defense => mt_rand(50,70)
);
$monsters[] = array(
   'name' => ‘ウォーターマン,
   attribute => ,
   'hp' => 200,
   'img' => 'monster02.png',
   'attack' => mt_rand(30, 80)
 ’defense => mt_rand(20,40)
);
$monsters[] = array(
   'name' => ‘ウッドマン,
   attribute => ,
   'hp' => 300,
   'img' => 'monster03.png',
   'attack' => mt_rand(10, 30)
 ’defense => mt_rand(90,150)
);

//以下略

こんな風に30体作っていくことになると思うのですが、これを抽象化して

「共通点を集めて、1つの雛形(テンプレート)を作れば保守性が上がるんじゃない?」

ということが、オブジェクトとして考えるってことだと今の所理解しています。

==============================================

保守性が高い、というのは以下の意味だと思っています。

  • あとから読んだときにわかりやすい
  • 変更しやすい、修正しやすい
  • バグを生みにくい

=============================================

オブジェクト指向でモンスターのクラスを作成【準備編】

モンスターの共通点は今回の例でいうと

・名前
・タイプ(火タイプとか、水タイプとか)
・見た目
・HP
・攻撃力
・防御力

になります。
これらはプロパティ(属性)というもので、
動きがあるものはメソッド(動き)と呼ばれます。

攻撃はプロパティだけど、攻撃するはメソッド。
足が3本はプロパティだけど、走るはメソッド。

という感じです。

①これらを予めモンスターの設計図として、テンプレートとして準備します。

このモンスターの共通点をクラスに入れ込みます。
この設計図が、クラスになります。

②クラスの中にコンストラクタを作成します。

コンストラクタは、クラスをインスタンス化した時に実行されるメソッド。
※newしたときにプロパティを設定したい場合、適用する関数(マジックメソッド)

③この設計図を元に、インスタンスを作成します。

僕のイメージですが、インスタンスの作成って
モンスター工場で、設計図を元にガッチャン!って金型でプレスして作るようなイメージでいるんですが
とにかく設計図を元に、インスタンスというものを作ります。
このインスタンスを作ることを「実体化」と言います。

オブジェクト指向でモンスターのクラスを作成【コード編】

実際のコードは

// モンスターたち格納用
$monsters = array();

// クラス(設計図)の作成
class Monster{
  // プロパティ
  public $name; 
  public $attribute;
  public $hp;
  public $img;
  public $attack; 
  public $defense; 

  // コンストラクタ
   public function __construct($name, $attribute, $hp, $img, $attack,$defense){
     // -> : アロー演算子は左辺から右辺を取り出す演算子
     $this->name = $name;
     $this->attribute = $attribute;
     $this->hp = $hp;
     $this->img = $img;
     $this->attack = $attack;
     $this->defense = $defense;
   }
 }

という感じです。
ひとまずこれでモンスターの設計図は出来上がり!
※アクセス権は一旦無視して作っています。

さて、次にインスタンスの作成ですが、

// インスタンス生成
$monsters[] = new Monster('ファイアーマン', 100, 'monster01.png', mt_rand(20, 40),mt_rand(50,70));
$monsters[] = new Monster('ウォーターマン', 200, 'monster02.png', mt_rand(30, 80),mt_rand(20,40));
$monsters[] = new Monster('ウッドマン', 300, 'monster03.png', mt_rand(10, 30),mt_rand(90,150));

という風になります。
【注意!】インスタンス生成時には、必ずnewを入れないといけません。

これで原型は出来上がり。

モンスター工場で、設計図を元にガッチャン!ってプレスしてモンスターが生まれました。

ここまでのまとめ

  • オブジェクトを作るには、設計図が必要です。
  • その設計図は「クラス」と言います。
  • クラスを元に出来上がるオブジェクトがインスタンス。
  • クラスの中にコンストラクタを入れれば、インスタンス生成時に呼び出される。
  • クラスにはプロパティと、メソッドを入れることができる。
  • オブジェクト指向で作っておくと、後で修正や変更がしやすい。
    (あとからやっぱり「MP」と「魔法攻撃する」を入れたいときには、MPのプロパティと魔法攻撃のメソッドをクラスに足すだけでインスタンスがそのプロパティとメソッドを持てる)

感想

オモシロイと思ったのは
何かオブジェクトを作ろうと思ったとき、連想配列でも出来るんだ!ということです。
ただ連想配列のkey&valueの1セット1セットが独立しているわけではなく、全部揃ってそのオブジェクトを表している、、、という表現で合っているんでしょうか?

連想配列の箱にただ順番にデータが入っているわけではなく、意味があってそのデータが入っているんですよね。
プロパティの情報が全部合わさって、一つの意味のあるクラスが出来上がる。というような。

奥が深いです!

今回は以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP Slim 環境構築(9) 設定ファイル

PHP Slim 環境構築(9) 設定ファイル

Introduction

前回は、ローカルS3(互換)をdockerで立てて、それにアクセスしてみました。
今回は、設定ファイルなどを少し整理してみます。

変更点

ソースツリー

前回からの変更・追加ソースは以下の通りです。

$(PROJECTROOT)
  /compose
    /web_front
      Dockerfile
      local.conf                           (default.confからのrename)
    /web_hoge
      Dockerfile
      php.local.ini
      settings.local.php
    docker-compose-common.yml              (docker-compose.ymlからのrename)
    docker-compose-local.yml
  /src
    /hoge
      /public
        index.php

/web_front/Dockerfile

Nginxの設定ファイルを環境(local, developmentなど)毎に変更できるように修正しました。
docker-composeでenvironment, environmentkeyを指定します。
なお、environmentが環境、environmentkeyが環境内の枝番(developement-1とかlocal-hogebranchとか)です。

/compose/web_front/Dockerfile
FROM nginx:1.17.3

ARG environment
ARG environmentkey=""

# settings
COPY ${environment}.conf /etc/nginx/conf.d/default.conf
RUN sed -i -e"s/{ENVKEY}/${environmentkey}/" /etc/nginx/conf.d/default.conf

RUN deluser www-data \
    && addgroup --system --gid 1000 www-data \
    && adduser --system --home /var/www --no-create-home --uid 1000 --gid 1000 \
       --disabled-password --disabled-login --shell /usr/sbin/nologin www-data

EXPOSE 3128
EXPOSE 8443

/web_front/local.conf

default.confからrenameしただけで中身は変更していません。
なお、開発用やテスト用サーバを立てる場合は、server_nameにサーバ名を指定することになります。
このとき、サーバ名に{ENVKEY}などを含めておくと、DockerfileでARG(environmentkey)と置換されます。

/compose/web_front/local.conf
...(略)...
server {
  listen 3128;
  listen 8443 ssl;
  server_name hoge.localhost;
...(略)...

/web_hoge/Dockerfile

phpの設定と、DB接続情報などを環境毎に変更できるようにしました。
/web_front/Dockerfileと同様に、docker-composeでenvironment, environmentkeyを指定します。

なお、php-fpmの設定は今回変更していませんが、php.iniと同様の方法で、/usr/local/etc/php-fpm.d/zz-overwrite.confなどに設定をコピーするようにすることで設定を変更することもできます。

/compose/web_hoge/Dockerfile
FROM php:7.3.9-fpm-alpine3.10

ARG environment
ARG environmentkey=""

...(略)...

# settings
COPY settings.${environment}.php /var/www/settings.php
RUN sed -i -e"s/{ENVKEY}/${environmentkey}/" /var/www/settings.php

# PHP conf
COPY php.${environment}.ini /usr/local/etc/php/conf.d/php.ini

RUN apk del --purge .build-deps \
  && docker-php-source delete \
  && rm -rf /var/cache/apk/* \
  && rm -rf /tmp/*

RUN deluser www-data \
    && addgroup -g 1000 -S www-data \
    && adduser -u 1000 -D -S -G www-data www-data

/web_hoge/php.local.ini

エラーログを出力するようにしています。出力先はphp-fpmのデフォルト設定である標準エラー出力になります。
したがって、docker-compose logsコマンドでエラーログを見ることができます。

/compose/web_hoge/php.local.ini
[PHP]
log_errors = On
display_startup_errors = On
error_reporting = E_ALL
upload_max_filesize = 256M

/web_hoge/settings.local.php

/src/hoge/public/index.phpのDIコンテナの設定部分を抜き出しただけです。

/compose/web_hoge/settings.local.php
<?php

return [
    'userdb' => [
        'host' => 'mysql',
        'dbname' => 'userdb',
        'user' => 'scott',
        'password' => 'tiger'
    ],
    'logdb' => [
        'host' => 'postgresql',
        'dbname' => 'logdb',
        'user' => 'root',
        'password' => 'hogehoge'
    ],
    'redis' => [
        'host' => 'redis'
    ],
    'dynamodb' => [
        'endpoint' => 'http://dynamodb:8000',
        'region' => 'ap-northeast-1'
    ],
    'storage' => [
        'endpoint' => 'http://storage:9000',
        'region' => 'ap-northeast-1'
    ]
];

docker-compose-common.yml, docker-compose-local.yml

前までのdocker-compose.ymlを環境依存の部分と非依存の部分で分けました。
そのため、docker-composeコマンドを実行する場合は、以下のように設定ファイルを指定する必要があります
(-fは指定した順序に読み込まれ、後に指定した設定によって上書きされます)。

$ docker-compose -f docker-compose-common.yml -f docker-compose-local.yml build

docker-compose-common.ymlは旧docker-compose.ymlからサーバ名などの部分を取り除いた部分になります。

/compose/docker-compose-common.yml
version: '3'

services:
  web_front:
    build:
      context: ./web_front
    ports:
      - "80:3128"
      - "443:8443"
    volumes:
      - ../certs:/etc/certs:ro
    container_name: web_front
    networks:
      - private_net

  web_hoge:
    build:
      context: ./web_hoge
    volumes:
      - ../src/hoge:/var/www/hoge
      - ../src/vendor:/var/www/vendor
    container_name: web_hoge
    networks:
      - private_net

  redis:
    build:
      context: ./redis
    volumes:
      - redis-data:/var/lib/redis
    ports:
      - "16379:6379"
    sysctls:
      - net.core.somaxconn=1024
    container_name: redis
    networks:
      - private_net

  mysql:
    build:
      context: ./mysql
    volumes:
      - mysql-data:/var/lib/mysql
    ports:
      - "13306:3306"
    container_name: mysql
    networks:
      - private_net

  postgresql:
    build:
      context: ./postgresql
    volumes:
      - postgresql-data:/var/lib/postgresql
    ports:
      - "15432:5432"
    container_name: postgresql
    networks:
      - private_net

  dynamodb:
    image: amazon/dynamodb-local
    container_name: dynamodb
    ports:
      - "18000:8000"
    networks:
      - private_net

  storage:
    image: minio/minio
    volumes:
      - storage-data:/data
    container_name: storage
    ports:
      - "19000:9000"
    environment:
      MINIO_ACCESS_KEY: minio
      MINIO_SECRET_KEY: miniminio
    command: server /data
    networks:
      - private_net

volumes:
  redis-data:
  mysql-data:
  postgresql-data:
  storage-data:

networks:
  private_net:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.28.0.0/24

逆に、docker-compose-local.ymlはdocker-compose-common.ymlから取り除かれた部分になります。

/compose/docker-compose-local.yml
version: '3'

services:
  web_front:
    build:
      args:
        - environment=local
        - environmentkey=

  web_hoge:
    build:
      args:
        - environment=local
        - environmentkey=
    environment:
      XDEBUG_CONFIG: "remote_host=172.28.0.1"
      PHP_IDE_CONFIG: "serverName=hoge.localhost"
    domainname: localhost

index.php

以前のソースで、ContainerBuilder::addDefinitionsを呼び出したとき設定していたsettingsを、外部から呼び出してきてセットするように修正しています。

/src/hoge/public/index.php
...()...

/** @var Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__ . '/../../vendor/autoload.php';
$loader->addPsr4('Hoge\\', __DIR__ . '/../lib');

$settings = require __DIR__ . '/../../settings.php';

$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions([
    'settings' => $settings,
    'userdb' => function (ContainerInterface $container) {

ここまでのソース

こちらでどうぞ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ローカル開発環境をmampからdockerに移した話

やりたかった事、背景

・元々の開発環境はmampだった
・新しくプロジェクトを追加する時、スクリプト動かしてvhost記述して、みたいな感じでめんどかった
・port番号が8888のせいでめんどい時があった(設定次第で別にmampでもできる)
・上司にdocker環境を進められて、興味があった
・社内で使っていたdocker開発環境だと自分の環境ではxdebugが動かなかった。また、その環境はコンテナがプロジェクトファイルのhtdocsフォルダに紐つけられていて、プロジェクトを再配置するのがだるかった

じゃあもうdockerで自分で環境作っちゃえ!!!

実際にやった事

・ローカル環境のhttps化(オレオレ)
・VirtualDocumentRootを使ってvhostをワイルドカード化した(超楽になった)
・xdebug動くようにした
・php5とphp7切り替えられるようにした
・mailhogつけた
importがめんどかったのでdbのデータもディレクトリ写すだけでできるようにした

dbのデータだけはなぜかできなかったので誰かプルリク投げてください。。。

いろんなサイト参考にしていいとこ取りしまくりました。。すみません。。。

レポジトリはgithubに公開してます。

docker-compose up -d で動きます。是非とも使用して、ガシガシ開発しましょう!!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Webプロ コマンドまとめ

用語

用語 解説
ディレクトリ ほぼ「フォルダ」と同じ意味(厳密には違う)
ホームディレクトリ パソコンに入っているアカウントごとに用意されているディレクトリ 基本的に作ったファイルはここの中に保存する(ワードやエクセルなどのファイルもそう)

ディレクトリ表示

  • lsとはlistの略
  • 自分が今いるディレクトリの一つ下にあるディレクトリの一覧が表示される
ターミナルorコマンドプロンプト
ls

ディレクトリ移動

  • cdとはchange directoryの略
  • {ディレクトリ名}のディレクトリに移動
  • {ディレクトリ名}はlsのコマンドを打ったときに出てくるディレクトリを入れる
ターミナルorコマンドプロンプト
cd {ディレクトリ名}

# 例
cd php7
cd Desktop 
  • 一つ上のディレクトリに移動
ターミナルorコマンドプロンプト
cd ..
  • ホームディレクトリに移動(次の2つのうちどちらでも良い)
ターミナルorコマンドプロンプト
cd 
cd ~

サーバー起動

  • PHPでサーバーを起動
  • 起動後にlocalhost:{数字}にアクセスするとアクセスできる
  • {ディレクトリ名}はlsのコマンドを打ったときに出てくるディレクトリを入れる
  • 大文字と小文字を打ち間違えるとうまく起動しない
ターミナルorコマンドプロンプト
php -S localhost:{数字} -t {ディレクトリ名}

# 例
php -S localhost:8080 -t htdocs
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

メモ - GAE/SE php72,73 ローカル実行時の設定

php73@gae でローカルでテストするときのメモ。

php72/73 では dev_appserver.py が無くなったので、普通に php インストールしてテストする。

が、普通に

php -S localhost:8080

とかやるだけだと、gaeにデプロイした時と違う挙動になる。

app.yaml
runtime: php73
entrypoint: serve --workers=4 --enable-dynamic-workers index.php 
index.php
<?php
switch (@parse_url($_SERVER['REQUEST_URI'])['path']) {
    case '/':
        require 'hello.php';
        break;
    case '/test':
        require 'test.php';
        break;
    case '/dir/test':
        require 'dir/test.php';
        break;
    default:
        http_response_code(404);
        exit('Not Found');
}

とかのデバッグをローカルでやる場合、

http://localhost:8080/test

は問題ないが

http://localhost:8080/dir/test

Not Found
The requested resource /dir/test was not found on this server.

となってしまう。

この場合、ビルトインウェブサーバーの起動時にルータースクリプトとして index.php を指定するとよい。

php -S localhost:8080 index.php

たぶん。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

phpのvar_dumpとvar_exportの違いをよく聞かれるので説明してみる

<?php
$hoge = [
  'aaa' => 'hoge',
  'bbb' => 'foo',
  'ccc' => 'bar',
];

var_dump($hoge);
var_export($hoge);

/////var_dump/////
array(3) {
  ["aaa"]=>
  string(4) "hoge"
  ["bbb"]=>
  string(3) "foo"
  ["ccc"]=>
  string(3) "bar"
}

/////var_export/////
array (
  'aaa' => 'hoge',
  'bbb' => 'foo',
  'ccc' => 'bar',
)

基本的には標準出力する分には同じです。
出力される構造としては上記のような違いになります。

var_export関数は var_dump() に似ていますが、 返される表現が有効な PHP コードであるところが異なります。

公式の言い方をするとvar_exportは、このような「有効なPHPコード」という形式になります。

ちなみに有効なPHPコードとは?という疑問もあると思います。
var_exportの第二引数にtrueを指定すると変数を出力せずに変数の値を返します。

なので、使用用途としてはログ出力時などに変数情報を文字列として出力するには
var_export()が適しています。

ex)

\Log::debug(var_export($hoge, true));

var_dumpは配列の要素数や型も表示されるので用途別で使い分けましょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HomebrewでPHP7.2のインストール(Mac)

install php for mac

mac OS version : 10.14.4
Homebrew : 2.1.9

参考1 : https://qiita.com/saken649/items/b5830de62211b600f7ee
参考2 : https://qiita.com/nemui_/items/cbf876db509e6a427541

homebrewはインストールしてあることが前提

phpのデフォルトバージョン確認

$ php -v
PHP 7.1.23 (cli) (built: Feb 22 2019 22:08:13) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
$ brew search php72
==> Formulae
php@7.2

$ brew install php@7.2
(前略)
If you need to have php@7.2 first in your PATH run:
  echo 'set -g fish_user_paths "/usr/local/opt/php@7.2/bin" $fish_user_paths' >> ~/.config/fish/config.fish
  echo 'set -g fish_user_paths "/usr/local/opt/php@7.2/sbin" $fish_user_paths' >> ~/.config/fish/config.fish
(後略)

pathを通す(おらのシェルはfishなので,bashとは少しコマンドが違う)

$ echo 'set -g fish_user_paths "/usr/local/opt/php@7.2/bin" $fish_user_paths' >> ~/.config/fish/config.fish
$ echo 'set -g fish_user_paths "/usr/local/opt/php@7.2/sbin" $fish_user_paths' >> ~/.config/fish/config.fish

再読み込みして通るか確認

$ source ~/.config/fish/config.fish
$ which php
/usr/local/opt/php@7.2/bin/php

$ php -v
PHP 7.2.22 (cli) (built: Sep 14 2019 18:36:32) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.22, Copyright (c) 1999-2018, by Zend Technologies

インストール完了.
rbenvみたいにversion切り替えできるようにしたいなぁ...

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

macでdocker-composeを使ってPHPとnginxをすぐに使えるようにする方法

PHPの勉強用に「折角だからnginxをdockerで立てて使おう〜」と軽い気持ちでコンテナ立てて実行しようとしたところ「コンテナのnginxのドキュメントルートにどうやってファイル置くんだろ。」とか「もしかしてコンテナ入って置かないとダメ?」とか前知識が無くて全然うまく行かず。。

docker-composeを使って速攻で準備

出来ねぇ出来ねぇボヤいてたらwebエンジニアにdocker-composeを使って速攻でその辺の環境を作る方法を教えてもらいました。
コンテナを立てたい場所に下記のdocker-compose.ymlファイルを作成します。

[docker-compose.yml]

### nginxでphpをブラウザ上に表記するのに必要なコンテナ一式。
version: '3'
services:
  app:
    image: laradock/php-fpm:2.2-7.2
    # ローカルのカレントディレクトリに格納したファイルをコンテナの/var/phpappにマウントする
    volumes:
      - ./:/var/phpapp/

  nginx:
    image: nginx:latest
    # 8080ポートから来た接続をコンテナの80番ポートに連携する
    ports:
      - "8080:80"
    volumes:
      # ローカルの./docker/nginx/nginx.confのをnginxコンテナの/etc/nginx/conf.d/default.confにマウントする
      - ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      # ローカルカレントディレクトリをコンテナの/var/phpappにマウント
      - ./:/var/phpapp/

  mysql:
    image: mysql:5.7
    # 33306ポートから来た接続をコンテナの3306番ポートに連携する
    ports:
      - 33306:3306
    volumes:
      - ./testdata/:/data
    environment:
        MYSQL_DATABASE: app
        MYSQL_ROOT_PASSWORD: root

あとnginx.confの内容を下記にします。
これはローカルの.docker/nginx/nginx.confに作成してください。

[nginx.conf]

server {
  listen 80;
  server_name localhost;
  root  /var/phpapp/web;
  index index.php index.html;
  location / {
    try_files $uri $uri/ /index.php$is_args$args;
  }

  location ~ \.php$ {
    fastcgi_pass   app:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;
  }
}

nginx.confの方は深く説明しませんが、この設定にしておけばローカルのカレントディレクトリのwebフォルダに格納したPHPファイルはちゃんと処理されてブラウザ上で表示されます。

あとはdocker-composeファイルを起動させれば準備完了します!

$ docker-compose up -d

出来たものはこちらです。

$ docker ps
CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS              PORTS                                NAMES
04e0f98cc4ef        mysql:5.7                  "docker-entrypoint.s…"   7 hours ago         Up 7 hours          33060/tcp, 0.0.0.0:33306->3306/tcp   memo_keizi_mysql_1
8c0639887fb3        laradock/php-fpm:2.2-7.2   "docker-php-entrypoi…"   23 hours ago        Up 23 hours         9000/tcp                             memo_keizi_app_1
c3574c4c67b9        nginx:latest               "nginx -g 'daemon of…"   34 hours ago        Up 33 hours         0.0.0.0:8080->80/tcp                 memo_keizi_nginx_1

IMAGEのところがdocker-composeのimageで記述したものになっています。

PHPをブラウザで表示させるところまで確認する

折角なので格納したPHPファイルがブラウザ上で表示されるところまで確認します。
※今回MySQLは使用しません。

nginx.confで設定したroot /var/phpapp/web;によりwebフォルダがドキュメントルートになります。
カレントディレクトリにwebフォルダを作成し、PHPファイルを格納します。

$ ls web/
index.php

ファイルの内容はありきたりですが、Hello World出力で。。

[index.php]
<html>
 <head>
  <title>PHP Test</title>
 </head>
 <body>
 <?php echo '<p>Hello World</p>'; ?> 
 </body>
</html>

http://localhost:8080/でアクセスすると、、

image.png

問題なく出力されました。
このwebフォルダにPHPのファイルを入れてパス指定すれば問題なく起動します。

終わりに

半端な知識で「nginxはコンテナで!PHPはローカルに入ってるからそれで勝手に処理してくれるでしょ!」くらいの軽い気持ちでやったら泥沼でした。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初心者向け】競技プログラミングざっくり入門【競プロ】

この記事の目的

競技プログラミング/プログラミングコンテストに参加し始めたばかりの自分が、コンテストや過去問を解く上で参考にしたサイト、困ったことなどをメモするほか、これから競技プログラミングに挑戦していこうという人たちの参考になれば。自分のレベル感としては最初の村を出たばかりで、ひのきのぼうと皮の盾装備。PHPerなので参考URLはPHP関連のものが多いです。競技プログラミングにおいてPHPerは少数派なので情報が少なく、それが動機ともなってこのような記事を書こうと思い至りましたが、実行速度や人気度などからC++, Pythonなどでもいずれやりたいなぁと思っています。

競技プログラミングとは

競技プログラミング(以下、競プロ)とは、プログラミング技術を競うコンテストのこと。いろいろな企業や団体が主催をしていて、世界中で毎日のように競技が開催されています。様々な言語の取り扱いがあり、自分の得意な言語でチャレンジ可能。オフラインのものは参加したことはありませんが、オンラインのコンテンスト問題は、与えられたお題に対して、正しい出力が期待されるコードを送信するだけで、機械的にジャッジされて得点や順位、レーティングが分かったりするので気軽に挑戦できるのが魅力かと思います。ここでは主にオンラインの競技プログラミングに関して取り上げています。

競プロいろいろ

国内サイト・大会

AtCoder
日本最大級の競プロサイト。

yukicoder
中規模なプログラミングコンテストサイト。

日本情報オリンピック(Japanese Olympiad in Infomatics(JOI))
高校生向けプログラミングコンテストの国際情報オリンピック(IOI)の代表選考のためのコンテスト。

paiza プログラミングスキルチェック
エンジニア向けラーニング&転職サービスですが、スキルチェックとして競プロに近いテストをオンラインでたくさん受けられます。

CODE VS
リクルートが主催するプログラミングコンテスト。

海外サイト

LeetCode
アメリカ・カリフォルニア発の競プロサイト。英語と中国語に対応。

HackerRank
アメリカにあるプログラミングコンテストサイト。

Topcoder
アメリカのAppirio社が提供するプログラミングコンテストサイト。

Codeforces
ロシアの大学 (Saratov State University) に所属するMike Mirzayanovらが実施するプログラミングコンテストサイト。

CodeChef
Directi社が運営・提供するプログラミング学習サイト。

Project Euler
数学の問題が出題されるようです。

国際大会

Google Code Jam (GCJ)
Googleが実施するプログラミングコンテスト。

Facebook Hacker Cup (FHC)
Facebookが実施するプログラミングコンテスト。

ACM-ICPC 国際大学対抗プログラミングコンテスト
大学対抗のプログラミングコンテスト。1970年から始まり今に続く歴史あるコンテスト。

2019 TopCoder Open
TopCoderが実施する祭典コンテスト。毎年開催され、年度によってURLも新設されるので注意が必要です。

ICFP Programming Contest (ICFPC)
関数型プログラミング言語のカンファレンスが実施するコンテスト。

Microsoft Imagine Cup
マイクロソフトが実施する学生向けのプログラミングコンテスト。

国際情報オリンピック(International Olympiad in Informatics) (IOI)
高校生向けのプログラミングコンテスト。参加するには日本情報オリンピックで代表に選ばれる必要があります。

AtCoderでのレーティングについて

AtCoderではレーティングのシステムが採用されていて、400ポイントごとにレベルが色分けされています。
高いものから、赤・橙・黄・青・水・緑・茶・灰・黒、という順番になっており、レベル感について詳しくは下記の記事でまとめていただいています。AtCoder主催の高橋直大さんのブログです。

AtCoder(競技プログラミング)の色・ランクと実力評価、問題例

競プロでたまに見る「標準入力」とは

その言語で想定される一般的な入力方法。入出力といえばキーボード入力・モニタ出力なども一般的ですが、競プロにおいてはテキストファイルまたは特定の値を保持したと仮定する変数、が入力の対象となることが多い印象です。
PHPの場合、変数からの入力であればそのまま使用できますが、テキストファイルからの入力が想定されるのであればfscanf()fgets()関数で取り回しできるようになることがまず必要です。

PHP マニュアル - fscanf
PHP マニュアル - fgets

ローカル環境でプログラムを実行して出力を確認する際は、ローカルにあるテキストファイルをfopen()関数で読み取って、fgets()関数で1行ずつ変数や配列に格納したり、echoreturnで返してあげたりすることから始めると良さそうです。
「標準入力から与えられた数値の合計を計算する」という問題が与えられたとして、仮に、入力用のテキストファイルをtest.txt、実行用のプログラムファイルをindex.phpとします。

test.txt
3
4
3

テキストファイルの取り出したい行に改行や空白が含まれて意図しない結果が出力される場合は、trim()関数で空白を削除することが可能です。

PHP マニュアル - trim

上記を踏まえ、ローカルでの実行内容としては以下のようなものが想定されます。

index.php
<?php
    // test.txt を r(読み取り専用)モードで開く
    $file = fopen("test.txt", "r");

    // fgets で1行ずつテキストファイルの中身を取り出して $line に代入
    // while でテキストファイルの最後の行まで繰り返すことができる
    while ($line = fgets($file)) {
        // trim で文字列 $line の先頭および末尾にあるホワイトスペースを取り除く
        // テキストファイルの全内容は1行ずつ配列として $temp[] に格納される
        $temp[] = trim($line);
    };

    echo $temp[0] + $temp[1] + $temp[2]; // 実行結果:10 (正解)

これをAtCoderなどのサイトで送信する場合は、ローカルでの入力は必要ないので、fopen()は削除してfgets($file)の代わりにfgets(STDIN)などとすれば問題なさそうです。STDINはスタンダート・インプットの略で、ソースは更に短く、下記のようになります。

index.php(提出用)
<?php
    while ($line = fgets(STDIN)) {
        $temp[] = trim($line);
    };
    echo $temp[0] + $temp[1] + $temp[2];

サイトによってはechoではなくreturnで返す場合もあるかと思います。
また、プログラムの書き方は1通りではないので、もっと短く効率的に書けるようであればそちらを優先してください。(例えば、配列の数値の合計を出す関数を使うともっとスマートに書けるかも、とか。)

今日はいったんここまでにしておきます。

参考URL

標準入力、標準出力とは何か?
http://www.creatology.jp/unix/outin.html#err
競技プログラミングとは?メリットや初心者にもおすすめな理由も解説
https://tech-camp.in/note/technology/43369/
【PHP】複数文字列の置換(str_replace)
https://qiita.com/kazu56/items/35c10fdd79393686b26d
Paizaで使える標準入力の取得
https://qiita.com/one-kelvin/items/09068b8971c4da509cd3
PHPで標準入力から値を取得して表示する方法を解説
https://qiita.com/yuhei_umeda/items/552c3f2f19e55f80fdfb
AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~
https://qiita.com/drken/items/fd4e5e3630d0f5859067#3-hello-world-----practice-contest-a-問題のみ
AtCoder用語集
https://atcoder.jp/contests/abc074/glossary?lang=ja
PHPの出力で文字を改行(\n)させるには’’(シングルコーテーション)じゃなくて""(ダブルコーテーション)で記述する
https://qiita.com/sola-msr/items/0814c4470dcbbd1f5ec3
asort(PHP 4, PHP 5, PHP 7) — 連想キーと要素との関係を維持しつつ配列をソートする
https://www.php.net/manual/ja/function.asort.php
配列のソート
https://www.php.net/manual/ja/array.sorting.php
PHPで割り算の余り、切り上げ、切り捨て、四捨五入する方法
https://www.flatflag.nir87.com/division-414
代数演算子
https://www.php.net/manual/ja/language.operators.arithmetic.php

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む