LoginSignup
15
13

More than 5 years have passed since last update.

PHP総復習チェックリスト ~最低限知っておくべき知識たち~

Posted at

PHPチェックリストです。
最低限知っておくべき知識たちです!
当たり前中の当たり前の知識については触れていなかったりします(echoとか)

学習というよりは振り返りとしてご活用ください!

文字列型、数値型、論理型について

英語名 よく使う書き方
文字列型 string str
数値型 integer, float int, float
論理型 boolean boolean

integerは整数、floatは少数が使えます。
文字列型や数値型はだいたい分かると思いますが、論理型とは何でしょう??

それは、TrueとかFalseを返すものをいいます。

ちなみに、var_dumpで、どの型なのかがわかります。

define

defineはこんな感じで使います。

define("name", "taro")
echo name

EMAILやディレクトリを定数で使うことが多いようです。

var_dump

var_dumpはデバッグでよく使われます。

$hello = "おはようございます"
var_dump($hello);

$greet = array("Good_Morning", "Hello", Good_Evening);
var_dump($greet);

結構var_dumpは使うのですが、僕が普段使わないvar_dumpの使い方を学びました。
こちらです。何だか使えそうですねえ。


var_dump(__LINE__) //現在の行数を表示
var_dump(__FILE__) //ファイル名を表示
var_dump(__DIR__) //ファイルのディレクトリを表示

文字列の中に変数を入れる

$hello = "おはようございます";
$greet = "朝の挨拶は{$hello}です。";
echo $greet; //朝の挨拶はおはようございますです。

次の書き方は個人的によく使う書き方で

$hello = "おはようございます";
$greet = "朝の挨拶は . $hello . です。";
echo $greet; //朝の挨拶はおはようございますです。

比較演算子

比較演算子はphpのマニュアルを見ると一番わかりやすいと思います。
php 比較演算子

宇宙船とかも使えるようになったら楽しいかもしれません!

条件分岐

条件分岐はif文を使う方法、三項演算子を使う方法、switch文を使う方法があります。

if文による条件分岐

条件分岐は、if、elseif、elseを使います。
オプショナルで三項演算子を使えるようになったら面白いかもしれない!

$score = 100;
if ($score = 100){
  echo "100点満点です!すごいですね!";
}elseif ($score > 80){
  echo "高得点です!あと少し!";
}else{
  echo "もう少し勉強しましょう。"
}

if文は真偽値でも判定できます。
下の文で用いている「!」は比較演算子にも出てきた否定を表す文字です。

$score = null;
if (!$score){ //scoreが偽だったら(nullか0だったら)
  echo "テストを受けていません。";
}else{
  echo "テストを受けています。";
}

三項演算子による条件分岐

さっきのif文は、三項演算子でこのように書き換えられます。
めっちゃコンパクトになりますね!!!

$score = 1;
$message = ($score) ?  "テストを受けています。" : "テストを受けていません。" ;
echo $message;

switch文による条件分岐

switch文による条件分岐はこのように書きます。
みやすいですよね。
caseでこの時はこうする、この時はこうする。みたいな。

$greet = "hello";

switch($greet){
  case "Good_Morning":
    echo "おはようございます";
    break;
  case "hello":
    echo "こんにちは";
    break;
  case "Good_Evening":
    echo "こんばんは";
    break;
  default: //どれにも当てはまらなかった場合
    echo "何か間違っていますよ。";
    break;
}

ループ処理

ループ処理はwhile文、do...while文、for文があります。
foreachは配列のところで紹介します。

while文によるループ処理

$a = 1;
while ($a < 10) {
  echo $a;
  $a++;
} //結果は「123456789」

do...while文によるループ処理


$a = 1;
do {
  echo $a;
  $a++;
} while ($a < 10); //結果は「123456789」

while文とdo...while文の違いは条件を前につけるか後につけるかです。

for文によるループ処理

for ($i=1; $i < 10; $i++) {
  echo $i;
}//結果は「123456789」

個人的にfor文が一番使うと思います。

途中でやめたい時にループの強制終了であるbreakを使うことができ、
途中でスキップしたいことが出てきた時に、continueを使います。

for ($i=1; $i < 10; $i++) {
  echo $i;
  if ($i == 5) {
    echo "5で強制終了します。";
    break;
  }
} //出力結果  123455で強制終了します。
for ($i=1; $i < 10; $i++) {
  if ($i%2  == 0) {
    echo $i;
    continue;
  }
}//出力結果  2468で強制終了します。

配列

$score = array(
  '佐藤' => 100,
  '田中' => 80,
  '渡辺' => 50
);

var_dump($score["佐藤"]); //int 100

この場合人の名前が「key」と呼ばれ、点数は「value」と呼ばれます。

key, valueという呼び名はよく使われるので覚えておくと良いでしょう。

valueを更新する際はこんな感じで書きます。

$score["渡辺"] = 70;

他にもこんな書き方があります。

$greet = ['Good_Morning', 'hello', 'Good_Evening'];
var_dump($greet[0]); //Good_Morning

これは、個人的にあんまり使わんなあ・・・。key,valueの方がわかり易い
forループで回すときは使うかもしれない。

foreachで配列をループ処理する

$scoresという配列があったときに、そのkey(この例でいうと名前)が$keyに、value(この例でいうと点数)が$valueに代入され、式で使えるようになります。

$scores = array(
  '佐藤' => 100,
  '田中' => 80,
  '渡辺' => 50
);

foreach ($scores as $key => $value) {
  echo $key . "さんのスコアは" . $value . "です";
}//出力結果 佐藤さんのスコアは100です 田中さんのスコアは80です 渡辺さんのスコアは50です

key valueでなくてももちろん使えます。

$greet = ['Good_Morning', 'hello', 'Good_Evening'];

foreach ($greet as $value) {
  echo $value;
}// 出力結果 Good_MorninghelloGood_Evening

foreachをHTMLに埋め込む時に使い易い構文

このような構文はforやwhile、ifにも存在するようです。

foreach ($greet as $value) :
  echo $value;
endforeach;
// 出力結果 Good_MorninghelloGood_Evening

これをHTMLで使うと、


<h1>挨拶をしましょう</h1>
<ul>
<?php foreach ($greet as $value) : ?>
  <li><?php echo $value; ?></li>
<? php endforeach; ?>
</ul>
<!--  
出力結果
挨拶をしましょう
Good_Morning
hello
Good_Evening
-->

関数

関数はとてもよく使います。
何回も同じことをしなければならない時に、関数にまとめると簡素化します。

例えば何か税抜きの値段を入れたら、税込の値段にしてくれる関数を作るとします。

function calcTax($price){
  $addTaxPrice = $price * 1.08;
  echo $addTaxPrice;
};

calcTax(100); //108

何も引数がなかった時の数値も定義することができます。
値引きとかで考えてみましょう。
値引きの引数がなかったら50円値引きするという特殊なスーパーがあるとしましょう。
5000円の品物の値引きはこのように関数化されます。

function nebiki($nebiki = 50){
  $afterNebikiPrice = 5000 - $nebiki;
  echo $afterNebikiPrice;
};

nebiki(); //4950
nebiki(100); //4900

ちなみにreturnをするとこうなります。

function nebiki($nebiki = 50){
  $afterNebikiPrice = 5000 - $nebiki;
  return $afterNebikiPrice; //returnに変更
};

nebiki(); //何も表示されない
echo nebiki(100); //4900

この関数の中で使われているとか$addTaxPriceとか$afterNebikiPriceは関数の外では使えません。ご注意ください。

組み込み関数

上記で述べた関数は自分で定義するものですが、すでに用意されている関数があります。
それを組み込み関数と言います。

例えば

//小数点切り上げ
echo ceil(5.3); //6

//小数点以下切り捨て
echo floor(5.5); //5

//四捨五入
echo round(5.5); //6

//乱数生成
echo rand(1,100); //1から100の間で乱数を生成する

//文字数を数える
//日本語の時はmb_が必要。英語の時は普通のstrlenで大丈夫。
echo mb_strlen("こんにちは"); //5

//配列などの要素の数を数える
$array = ["a", "b", "c"];
echo count($array); //3

//配列の要素をある区切り文字で区切る
$array = ["a", "b", "c"];
echo implode("|", $array) //a|b|c

printfはちょっとややこしいのでサイトをはっつけときます。
そふぃのPHP入門 printf

クラス, インスタンス

クラスが持つ変数をプロパティという
クラスが持つ関数をメソッドという

このクラスを元に実際にデータを持たせたものをインスタンスという

クラスやインスタンスについてをわかりやすく知りたい場合はこちらのサイトがおすすめです。
世界一わかりやすくクラスとインスタンスを説明する
こちらはphpではなくswiftで解説しているので、実際のコードは参考にすべきではありませんが、クラスとインスタンスについて結構わかりやすく書かれています。

そして、phpで実際のコードはどうなってるの?って気になる方はこちらを参考にしてもらったらわかりやすいです。
【PHP】クラスの基本 | インスタンス | プロパティとメソッド | オブジェクト指向

実際にちょこっとだけクラスとインスタンスについてのコードを書いてみます。
我ながら意外とわかりやすいかも。

class User{
  public $name; //プロパティ
  public $age; //プロパティ
  public $email; //プロパティ

  //コンストラクターの定義、インスタンスの生成時に必ず実行される。
  public function __construct($name, $age, $email){
    $this->name = $name; //$thisはこのクラスのという意味で、コード自体は「このクラスのnameプロパティに引数で渡された$nameを格納するという意味」
    $this->age = $age;
    $this->email = $email;
  }

  //メソッドの定義
  public function dataConfirm(){
    echo "お名前" . $this->name ;
    echo "ご年齢" . $this->age ;
    echo "email" . $this->email;
  }
}//ここまででクラスの定義が完了

/*
クラスはテンプレみたいなもので、
インスタンスを作って、具体的なデータを格納していく

次のインスタンスでは例として、山田さんと田中さんのインスタンスを作るとする
*/


/*
Userクラスの新しいインスタンスを作る(Userクラスというテンプレをコピーして山田さんのデータを入れていくイメージなのかな?)
new Userの後のかっこの中は、コンストラクターの引数に入れるデータ
なので、名前はyamada, 年齢は20, メールアドレスはyamada@yahoo.co.jp というデータを入れるということを表している。
田中さんも同様。
前述した通り、インスタンスの生成時に必ずコンストラクターが実行される。
*/
$yamada = new User("yamada", "20", "yamada@yahoo.co.jp");
echo $yamada->name; //yamada
echo $yamada->age; //20
echo $yamada->email; //yamada@yahoo.co.jp
$yamada->dataConfirm(); //お名前yamadaご年齢20emailyamada@yahoo.co.jp

$tanaka = new User("tanaka", "52", "tanaka@gmail.com"); //Userクラスの新しいインスタンスを作る
echo $tanaka->name; //tanaka
echo $tanaka->age; //52
echo $tanaka->email; //tanaka@gmail.com
$tanaka->dataConfirm(); //お名前tanakaご年齢52emailtanaka@gmail.com

クラスの継承

クラスで定義したプロパティやメソッドを他のクラスでも使いたい場合に、クラスを継承します。

class User{
  public $name; //プロパティ
  public $age; //プロパティ
  public $email; //プロパティ

  //コンストラクターの定義、インスタンスの生成時に必ず実行される。
  public function __construct($name, $age, $email){
    $this->name = $name; //$thisはこのクラスのという意味で、コード自体は「このクラスのnameプロパティに引数で渡された$nameを格納するという意味」
    $this->age = $age;
    $this->email = $email;
  }

  //メソッドの定義
  public function dataConfirm(){
    echo "お名前" . $this->name ;
    echo "ご年齢" . $this->age ;
    echo "email" . $this->email;
  }
}

/*
extendsを使うことでクラスの継承ができる
この場合、Userが親クラスで、MainUserが子クラスという
子クラスであるMainUserは親クラスであるUserで定義されているプロパティやメソッドが使える!
*/

class MainUser extends User{
  public function mainUserDataConfirm(){
    echo $this->name . " さんはメインユーザーとして登録されています。";
  }
}

$watanabe = new MainUser("watanabe", "45", "watanabe@yahoo.co.jp");
echo $watanabe->name; //watanabe
echo $watanabe->age; //45
echo $watanabe->email; //watanabe@yahoo.co.jp
$watanabe->dataConfirm(); //お名前watanabeご年齢45emailwatanabe@yahoo.co.jp

$watanabe->mainUserDataConfirm(); //watanabe さんはメインユーザーとして登録されています。

ちなみに、メソッドを再定義するオーバーライドも知っておきましょう。

Userクラスの「dataConfirm()」をMainUserクラスにオーバーライドしてみたいと思います。

class User{
  public $name; //プロパティ
  public $age; //プロパティ
  public $email; //プロパティ

  //コンストラクターの定義、インスタンスの生成時に必ず実行される。
  public function __construct($name, $age, $email){
    $this->name = $name; //$thisはこのクラスのという意味で、コード自体は「このクラスのnameプロパティに引数で渡された$nameを格納するという意味」
    $this->age = $age;
    $this->email = $email;
  }

  //メソッドの定義
  public function dataConfirm(){
    echo "お名前" . $this->name ;
    echo "ご年齢" . $this->age ;
    echo "email" . $this->email;
  }
}

/*
dataConfirmメソッドをMainUserでオーバーライド(再定義)してみる
*/

class MainUser extends User{

  //オーバーライドします
  public function dataConfirm(){
    echo "メインユーザーとして登録されています";
    echo "お名前" . $this->name ;
    echo "ご年齢" . $this->age ;
    echo "email" . $this->email;
  }
}
$yamada = new User("yamada", "20", "yamada@yahoo.co.jp"); //Userクラスのインスタンスを生成
$yamada->dataConfirm(); //お名前yamadaご年齢20emailyamada@yahoo.co.jp

$watanabe = new MainUser("watanabe", "45", "watanabe@yahoo.co.jp"); //MainUserクラスのインスタンスを生成
$watanabe->dataConfirm(); //メインユーザーとして登録されていますお名前watanabeご年齢45emailwatanabe@yahoo.co.jp

うまい具合にオーバーライドできました!!

でも、システム開発する時って、一人でやることはほとんどなくて、メンバーを何人か集めてプロジェクトとして動くことが多いです。
なので、このメソッドはオーバーライド禁止!!ってしたいのに、他のメンバーがオーバーライドしたら困りますよね。。

その時のオーバーライド禁止!!っていう暗号が「final」です。

final public function dataConfirm(){
}

と書いていたら、このメソッドはオーバーライド禁止!!ということになります。
オーバーライドした際にエラーが出ます。

アクセス権

さっきまでメソッドを定義する時に、public functionと書いていましたが、この「public」はどこからでもアクセス可能という意味です。

他に、privateやprotectedがあります。
まとめると

名前 アクセス権
public どこからでもアクセス可能
protected そのクラス内 + 親クラス + 子クラスからアクセス可能
private そのクラス内からのみアクセス可能

アクセス権:private

a.php
class Hello{
  private function message(){
  echo "クラス内からしか参照できないよ";
  }
  //ここはmessageメソッドを使えます。
}

class Hello2 extends Hello{
//ここはmessageメソッドは使えません。
}
b.php
class GoodBye{
  //ここはmessageメソッドは使えません。
}

アクセス権:protected

a.php
class Hello{
  protected function message(){
  echo "クラス内+親子クラスから参照できるよ";
  }
  //ここはmessageメソッドを使えます。
}
class Hello2 extends Hello{
//ここはmessageメソッドを使えます。
}

b.php
class GoodBye{
  //ここはmessageメソッドは使えません。
}

アクセス権:public

a.php
class Hello{
  public function message(){
  echo "どこからでもカモン";
  }
  //ここはmessageメソッドを使えます。
}

class Hello2 extends Hello{
//ここはmessageメソッドを使えます。
}
b.php
class GoodBye{
  //ここはmessageメソッドは使えます。
}

staticキーワード

staticを使用すればクラスをインスタンスせずともクラス内のメソッドを使えます。
注意点はインスタンスかしないので、コンストラクターを発動させないということです。

class Hello{
  function static message(){ //ここでstaticと書くとstaticになります。
  echo "これはstaticです。";
  }
}

Hello::message() //クラス名::メソッド名 という書き方

メソッドだけではなく、プロパティでも使えます。

class Hello{
  public static $count;
  function static message(){ //ここでstaticと書くとstaticになります。
  echo "これはstaticです。";
  self::$count++ //カウントアップする このクラスの$countとしたいときは「self」を使う
  }
}

Hello::message() //クラス名::メソッド名 という書き方

抽象クラス

抽象クラスは継承されることが前提で、それ自身はインスタンス化できないそうです。
抽象クラスを作る際には「abstract」を使います。

abstract class BaseUser{
  public $name;
  abstract public function show(){
  }
}

class MainUser extends BaseUser{
  public function show(){ //抽象クラスに書いてあるメソッドは全て実装しなければならない
  echo "あなたはメインユーザーです";
  }
}

class NormalUser extends BaseUser{
  public function show(){ //抽象クラスに書いてあるメソッドは全て実装しなければならない
  echo "あなたはノーマルユーザーです";
  }
}

抽象クラスに書いてあるメソッドは全て実装しなければならないため、実装漏れが防げます!
しかも、抽象クラスでプロパティとかメソッドとかをある程度定義しておくと、子クラスの実装がシンプルになります!

インターフェース

インターフェースは、このメソッドは必ず定義してくださいね〜というルールを定義するものです。
まあ、システム開発とかって何人も一緒にやるから、ルールを定義してないとやってらんないよね。。

インターフェースでメソッドを定義する場合、必ずpublicではないといけないことに注意しましょう。

interface showName{
  public function showName(); //クラスの方で具体的なコードを書くので、ここではこの関数は必須だよという定義だけでオーケー
}

interface showAge{
  public function showAge();
}


/*
クラスに実装してほしいインターフェースがあれば「implement」を使って、何を使用しなければいけないかのルールを決める
*/

class User implement showName, showAge{
  public function showName(){
  echo "こんにちは、田中です。";
  }

  public function showAge(){
  echo "21歳です";
  }
}

外部ファイルを読み込む

外部ファイルを読み込むには「require」「require_once」「include」「include_once」やautoloadなどがあります。

requireとincludeの違い

どちらもファイルを読み込むという点では一緒なのですが、「require」はファイルの読み込みエラーが起こった際に、「fatal error」を出して、そこで処理を中断します。

「include」はファイルの読み込みエラーが起こった場合に、「Warning」を出しますが、処理自体は実行します。

_onceが付いているものと付いていないものの違い

requireとrequire_once
includeとinclude_onceと、「_once」が付いているものと付いていないものがあります。

requireやincludeは、とりあえずファイルを読み込みます。

require_onceやinclude_onceはすでにそのファイルが読み込まれているかどうかをphpが自動でチェックして、読み込まれていたらその手順をスキップするというものです。

名前空間

クラス名やメソッド名などが、他のクラスの名前、メソッドの名前と被ってしまったらああ大変。
そうなるとややこしいので、名前空間を作り、その名前空間の中でクラス名やメソッド名を定義すれば、他の名前空間のクラス名やメソッド名と被っても大丈夫!

いろんなところでクラス名やメソッド名が錯綜しているところに、名前空間という仕切りをつけるようなものでしょうか。

もちろん、名前空間の被りがないように!!!

user.php

/*
名前空間の定義。ファイルの一番上で定義しなければならない。(もちろん、コメントは大丈夫・・・笑)
名前空間は、階層的に定義できます!
ディレクトリみたいですね!!
*/
namespace Register;

class User{
  public $name; 
  public $age; 

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

  public function dataConfirm(){
    echo "お名前" . $this->name ;
    echo "ご年齢" . $this->age ;
  }
}

名前空間の指定とクラスやメソッドの定義ができたので、次は、このクラスを他の場所で使ってみましょう。


include user.php; //ここ適当です。ごめんなさい。上のHello.phpを読み込んでいるとします。

$tanaka = new Register\User("tanaka", "8"); //名前空間を利用してインスタンスの生成。new 名前空間 クラス名 というような感じです。
$tanaka->dataConfirm();

今はまだ名前空間は短いのですが、色々増えていくと名前空間が長くなることがあります。

その時にめっちゃ有能な奴が「use」です。

//例えば、このような名前空間があると仮定します。
namespace \Register\User\AdminUser;

いやあ、3個全部書くのは長いですね!
このように長くなってしまった時に、useを使います。

上の奴はこうやって名前を変えることができます。

use \Register\User\AdminUser as User;

$tanaka = new User\AdminUser\User("tanaka", "24"); //インスタンス生成

こんな感じで使えます。

例外処理

例外処理はtryとcatchを使います。


function divide($a, $b){
  try{
    if($b == 0){
      throw new Exception ("0では割り切れません");
    }
    echo "$a / $b";
  }catch(Exception, $e){
    echo $e->getMessage(); 
  }
}

devide(5, 0); //0では割り切れません
devide(4, 2); //2

サーバー変数

サーバー変数の一部を紹介します。
$_SERVER['REQUEST_METHOD']は、postかgetを受け取ります。

例えばこんな使い方があります。

if($_SERVER['REQUEST_METHOD'] === 'POST'){
   //postを受け取った時の処理
}
elseif($_SERVER['REQUEST_METHOD'] === 'GET'){
  //getを受け取った時の処理
}
else{
  //どっちでもないときにエラーを出す処理
}

もしくは、バリデーションとかもできます。

if($_SERVER['REQUEST_METHOD'] === 'POST'){
   $name = $_POST['name'] //nameを受け取る
  if(!($name)) //nameがFALSE(0かnull)のとき{
  echo "名前が入力されていません";
  }
}

サーバー変数は結構たくさんあるので、いろんなのを知るとまた面白いですね。

PHP($_SERVER)サーバー変数一覧と実用例

htmlspecialcharacters

postで値を受け取った時は、あまりそのデータを信用してはいけません。

実はフォームで送信する場合に、攻撃されることがよくあります。
名前だったら田中とか、山田とか入力する分には大丈夫なのですが、記号を入れられるとシステムがヘンテコなことになることがあります。

それはXSS(クロスサイトスクリプティング)といって、結構メジャーな攻撃方法です。

これから身を守る方法の一つとして、htmlspecialcharactersがあります。
参考サイト
【PHP】XSSとは-----対策

ユーザーからpostなどでもらったデータにはmhtmlspecialcharactersを使用しましょう!

if($_SERVER['REQUEST_METHOD'] === 'POST'){
   $name = $_POST['name'] //nameを受け取る
}

echo htmlspecialcharacters($name, ENT_QUOTES, 'UTF-8');

と、まあこんな感じでしょうか。

Cookie(クッキー)

クッキーを使うと、ユーザーのブラウザにデータをセットすることができます。

データはキーとバリュー(配列の時にやりましたね)でセットすることができます

クッキーはブラウザに保存されるため、同じブラウザからアクセスすれば、
どこからでも$_COOKIE["name"]で「yamada」を呼び出せます


<?php

setcookie("name", "yamada"); //クッキーでデータをセット
echo $_COOKIE["name"]; //yamada

クッキーは第三引数も取れる。
第三引数は、クッキーの有効期限を決めることができる。有効期限を決めない場合は、ブラウザを閉じるまで有効!
1時間後にクッキーで保存したデータが使えなくなるように設定する場合には、このように書く


setcookie("name", "yamada", time()+60*60); //time()は今の時間を取得 60*60は60秒×60分という意味

クッキーを削除する場合は、有効期限を過去に設定するという意味で、time()+だったものをtime()-にしてあげる


setcookie("name", "yamada", time()-60*60);

セッション

セッションもクッキーみたいな感じで、アクセスして来たブラウザに応じてデータを保存する仕組みです。
クッキーはブラウザにデータを保存するけど、セッションはサーバー側にデータを保存する仕組みです。


//セッションを始めるときは必ずこれを行う
session_start(); //これはいつ何時でも 必要。セッションを定義するときも、セッションのデータを取り出すときだけでも

$_SESSION["name"] = "yamada"; //これで、サーバーにデータが保存された

echo $_SESSION["name"]; //yamada

クッキーと同じように、アクセスしたブラウザに応じてデータを保存しているので、他のファイルからアクセスしてきても$_SESSION["name"]は有効

セッションの削除はunsetを使います


unset(echo $_SESSION["name"]);

クッキーはお手軽に使える一方で、データが改ざんする恐れがあり、やろうと思えばデータが見れることもあリます。
セッションは大きなデータを保存できたり、改ざんされない、中身が見られないという特徴があります。

仕事をしていて分からなかったことメモ

これは、随時追記していきます。

「??」

はてな二つを使うときがあります。

はてな二つの左側の値がnullだった場合に右側を実行する、左側がnullじゃなかったら左側を実行するという感じだそうです。

$greet = "こんにちは";
echo $greet ?? "さようなら" //こんにちは
$greet = null;
echo $greet ?? "さようなら" //さようなら
15
13
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
15
13