React 復習

JSX

// { } でJavaScriptの記法と認識される
<button onClick={}>ボタン</button>
// 外側の{ } はJavaScriptの記法と認識される
// 内側の{ } はJavaScriptのオブジェクトのこと
<h1 style={{ color: 'red' }}>こんにちは!</h1>

イベント発火

export const App = () => {
  const onClickButton = () => alert();

  return (
    <div>
      <button onClick={onClickButton}>ボタン</button>
    </div>
  )
}

Props

コンポーネントに対して渡す引数のようなもの

import { HelloWorldMessage } from "./components/HelloWorldMessage";

// コンポーネントに対して値を渡す
<HelloWorldMessage message="hello" />
<HelloWorldMessage message="world" />
// propsを受け取る(helloとworldが表示される)
export const HelloWorldMessage = (props) => {

  return (
    <p>{props.message}</p>
  );
}

children

タグで囲った値をchildrenとして渡すこともできる

import { HelloWorldMessage } from "./components/HelloWorldMessage";

// コンポーネントに対して値を渡す
<HelloWorldMessage>
  hello
</HelloWorldMessage>
<HelloWorldMessage>
  world
</HelloWorldMessage>
// propsを受け取る(helloとworldが表示される)
export const HelloWorldMessage = (props) => {

  return (
    <p>{props.children}</p>
  );
}

分割代入

分割代入で毎回propsを指定しなくてもよくなる

export const HelloWorldMessage = (props) => {
  const { color, children } = props;

  const contentStyle = {
    color: color,
    // ↑オブジェクトのプロパティ名と当てはめる値が同じ時は省略できる↓
    color,
    fontSize: '18px',
  };

  return (
    <p style={contentStyle}>{children}</p>
  );
}

State

コンポーネントが持つ状態(可変)

useState

import { useState } from "react";

// 第一引数:stateとして使用する変数名
// 第二引数:stateを変更するた関数名
// useState('初期値')を設定できる
const [num, setNum] useState(0);

<p>{num}</p> // 0

ボタンをクリックするとnumの値が1ずつ増えるイベント

import { useState } from "react";

export const App = () => {
  const [num, setNum] = useState(0);

  const onClickCountUp = () => {
    setNum((prevNum) => prevNum + 1);
  };

  return (
    <div>
      <button onClick={onClickCountUp}>カウントアップ</button>
      <p>{num}</p>
    </div>
  );
};

※js

// アロー関数はreturnで返す行が一行の時は省略できる
const a = (str) => {
  return str
}

// ↓
const a = (str) => str;

// ↓( ) も省略することもできる
const a = str => str;

// && 左辺がtrueの時に右辺を返す、左辺がfalseの時は右辺を返さない
{faceShowFlag && <p>orz</p>}

// || は左辺がfalseなら右辺を返す、左辺がtrueの時は右辺を返さない
{faceShowFlag || <p>orz</p>}

useEffect

Stateの更新があった時に再描画される(set関数が呼ばれてstateが更新された時に関数コンポーネントが頭から読み込まれる)
このような特定の条件の時にコンポーネントを再レンダリングして差分を反映することで
画面遷移を表現している

●再レンダリングする条件

・stateを変更した時
・コンポーネントのpropsの中身が変更した時
・親のコンポーネントが再レンダリングされた時(子コンポーネントも追随していく)
// useEffectの引数に空の配列[]を設定するとコンポーネント内で最初の1回だけ通したい処理を実行することができる
useEffect(() => {
    console.log('useEffect');
  }, []);
// 引数にnumを設定した場合、このuseEffectはnumにだけ関心を持つようになる
// そのため今回であればnumのstateが変更した時だけuseEffectが通るようになる
useEffect(() => {
    console.log('useEffect');
  }, [num]);
const [faceShowFlag, setFaceShowFlag] = useState(false);

useEffect(() => {
    if (num % 3 === 0) {
      // faceShowFlagがfalseの時だけset関数を呼び出しtrueに変更する
      faceShowFlag || setFaceShowFlag(true);
    } else {
      // faceShowFlagがtrueの時だけset関数を呼び出しfalseに変更する
      faceShowFlag && setFaceShowFlag(false);
    }
  }, [num]);

●行うこと
・ボタン(on/off)をクリックすると顔文字を表示・非表示にする
・3の倍数の時だけ顔文字を表示する

/*eslint react-hooks/exhaustive-deps: off */
import { useEffect, useState } from "react";

export const App = () => {
  const [num, setNum] = useState(0);
  const [faceShowFlag, setFaceShowFlag] = useState(false);

  const onClickCountUp = () => {
    setNum((prevNum) => prevNum + 1);
  };

  const onClickSwitchShowFlag = () => setFaceShowFlag(!faceShowFlag);

  //  「Too many re-renders」が発生するため引数にnumを指定し、このuseEffectはnumにだけ関心を持つように設定する
  useEffect(() => {
    if (num <= 0) {
      return
    }
    if (num % 3 === 0) {
      // faceShowFlagがfalseの時だけset関数を呼び出しtrueに変更する
      faceShowFlag || setFaceShowFlag(true);
    } else {
      // faceShowFlagがtrueの時だけset関数を呼び出しfalseに変更する
      faceShowFlag && setFaceShowFlag(false);
    }
  }, [num]);

  return (
    <div>
      <button onClick={onClickCountUp}>カウントアップ</button>
      <br/>
      <button onClick={onClickSwitchShowFlag}>on/off</button>
      <p>{num}</p>
      {faceShowFlag && <p>orz</p>}
    </div>
  );
};

Todo

import { useState } from "react";
import "./styles.css";

export const App = () => {
  const [incompleteTodos, setIncompleteTodos] = useState(['テスト1', 'テスト2']);
  const [completeTodos, setCompleteTodos] = useState(['テストend']);

  return (
    <div>
      <div className="input-area">
        <input placeholder="TODOを入力" />
        <button>送信</button>
      </div>
      <dir className="incomplete-area">
        <p className="title">未完了のTODO</p>
        <ul>
          {incompleteTodos.map((todo) => {
            return (
              <div key={todo} className="list-row">
                <li>{todo}</li>
                <button>完了</button>
                <button>削除</button>
              </div>
            )
          })}
        </ul>
      </dir>
      <dir className="complete-area">
        <p className="title">完了したTODO</p>
        <ul>
          <div className="list-row">
            <li>テストend</li>
            <button>戻す</button>
          </div>
        </ul>
      </dir>
    </div>
  );
};
const [incompleteTodos, setIncompleteTodos] = useState(['テスト1', 'テスト2']);

// ループ処理させる場合、ループ内で返却している一番親タグにkeyの指定が必要
// 変更前と変更後で差分だけ抽出しその差分のみ実際のDOMに反映していくため、ループでレンダリングされた場合、何個目の要素なのかを正確に比較するために目印をつける必要がある
{incompleteTodos.map((todo) => {
  return (
    <div key={todo} className="list-row">
      <li>{todo}</li>
      <button>完了</button>
      <button>削除</button>
    </div>
  );
})}

inputタグに入力した値を取得・追加

const [todoText, setTodoText] = useState('');

// 引数にイベントを受け取る
// e.target.valueで入力した値を取得しsetTodoText関数で更新する
const onChangeTodoText = (e) => setTodoText(e.target.value);

  const onClickAdd = () => {
    if (todoText === '') return alert('TODOを入力してください');

    // スプレッド構文で現在のincompleteTodosの中身を複製しtodoTextで新しい配列を生成(newTodos)
    // 新しく生成したnewTodosをsetIncompleteTodos関数で更新
    const newTodos = [...incompleteTodos, todoText];
    setIncompleteTodos(newTodos);
    setTodoText('');
  };

// onChangeでinputの値に変更があれば検知する(onChangeがないと初期値の空文字が設定され続ける)
<input placeholder="TODOを入力" value={todoText} onChange={onChangeTodoText} />
<button onClick={onClickAdd}>送信</button>

関数に引数を渡したい場合

// アロー関数を使い新しく関数を生成する必要がある
<button onClick={() => onClickDelete(index)}>削除</button>

削除

const onClickDelete = (index) => {
  const newTodos = [...incompleteTodos];
  // splice() 第一引数に何番目の要素か、第二引数にいくつ削除するか指定する
  newTodos.splice(index, 1);
  // このnewTodosでsetIncompleteTodosを更新する
  setIncompleteTodos(newTodos);
}

<ul>
  {incompleteTodos.map((todo, index) => {
    return (
      <div key={todo} className="list-row">
        <li>{todo}</li>
        <button>完了</button>
        <button onClick={() => onClickDelete(index)}>削除</button>
      </div>
    );
  })}
</ul>

PHP基礎

<?php
// シングルクォーテーションまたはダブルクォーテーションが必要
// function(パラメータ); という構文となる
// print 文字列を出力する
// print(string $arg) :int
// 終了タグ(?)は必要ない(省略できる)
print('PHPで出力しています');

// echo(string $arg1 [, string $...]) : void
// voidは何もない(値を返さない)
// echoはパラメータを複数とることができる
// echoは関数ではないため( )を省略することができる
echo '/ echoで出力しています', '/ 2つめの文章です', '/ 3つめの文章です';

// エスケープシーケンス
echo 'I\'am Japanese';
echo "I am \"Japanese\"";

// 改行
// シングルクォーテーションで囲うとそのまま出力される
// エスケープシーケンスを使うときはダブルクォーテーション
echo "\n改行を\n入れて出力します\n";

// ヒアドキュメント構文(<<<)
// 文字列を区切る方法
echo <<< EOT
あああああ
いいいいいい
ううううううううう
ええええええええええええええ
EOT;

echo "\n □Nowdoc";
// Nowdocはヒアドキュメントと似ているが、シングルクォートで囲んだ文字列として扱われる
echo <<< 'EOT'
あああああ
いいいいいい
ううううううううう
ええええええええええええええ
EOT;

算術演算子

<?php
echo 1+2;
echo "\n";
echo 10*3;
echo "\n";
echo 10/3;
echo "\n";

// 乗除算
echo 12%3;
echo "\n";

// 累乗
echo 2*3;
echo "\n";

変数

<?php
$price = 150+80;
$price = 10;
echo $price;
echo "\n";
echo $price*1.1;

$x;
$number_123;
$_123;
// $123; // ×数字から始まる
// $nuber-123; // ×ハイフン
// $_SERVER = 10; // ×予約語

$price = 100;
// 文字列連結 .
echo '50 + 50 は、' . $price . 'です';

$number = 10;
echo "{$number}th anniversary"; // 10th anniversary

定数

<?php
// 定数は慣習として大文字で定義する
const TAX = 10;

// 非推奨
// define(TAX, 10);

echo "消費税は、", TAX, "%です";

関数

<?php
$sum = 5000 + 150;
// number_format 数字を千位毎にグループ化してフォーマットする
// number_format ( float $number [, int $decimals = 0 ]) : string
// パラメータの中の[]は省略可能という意味
// []を省略した場合は0となる
$sum = number_format($sum);
echo $sum, '円です';
<?php
echo '足される数 >';
// STDIN ユーザのキーボードの入力を受け付ける
// fgets ファイルオブストリームから文字列を取得
// trimで改行を取り除く
$number = trim(fgets(STDIN));

echo '足す数 >';
$number2 = trim(fgets(STDIN));

echo $number . ' + ' . $number2 . ' = ' . $number + $number2;

制御構造

if構文

<?php
echo '数字を入力してください';
$number = trim(fgets(STDIN));

// 10よりも大きいかを判断する
if ($number > 10) {
  echo '10よりも大きいです';
} else {
  echo '10以下です';
}

if ($number > 10):
  echo '10よりも大きいです';
else:
  echo '10以下です';
endif;

elseif

if ($number > 10) {
  echo '10よりも大きいです';
} elseif ($number == 10) {
  echo '10です';
} else {
  echo '10以下です';
}
<?php
$number = 10;

// is_numeric 変数が数字または数値形式の文字列であるかを調べる
// 数値または数値形式の文字列である場合にTRUE、それ以外の場合にFALSEを返す
// $numeric = is_numeric($number);

if (is_numeric($numeric)) { // trueを省略
  echo '数字です';
} else {
  echo '数字ではありません';
}

echo '西暦を入力してください';
$year = trim(fgets(STDIN));

if (is_numeric($year) && $year <= date('Y')) {
  // echo '数字が入力されました';
  if ($year >= 2018) {
    echo '令和です';
  } elseif ($year >= 1988) {
    echo '平成です';
  } elseif ($year >= 1925) {
    echo '昭和です';
  } elseif ($year >= 1911) {
    echo '大正です';
  } elseif ($year >= 1867) {
    echo '明治です';
  } else {
    echo '明治よりも前です';
  }
} else {
  echo '今年よりも前の数字を入力してください';
}

$sum = 10 + 5;
echo $sum;

// 変数の再代入
// $sum = $sum + 20;
$sum += 20;
$sum -= 20;
$sum *= 20;
$sum /= 20;

// インクリメント・デクリメント
// $sum += 1;
$sum++; // インクリメント
$sum--; // デクリメント
echo $sum;

データ型と型キャスト

<?php
$number1 = 10; // int型
$number2 = '10'; // string型

// === $number が $numberに等しく、同じ型である場合にTRUE
// (int)でint型に型キャスト
if ($number1 === (int)$number2) {
  echo '同じです';
}

switch構文

<?php
echo '色を選んでください(1.黒, 2.しろ, 3.赤)';
$color = (int)trim(fgets(STDIN));

// if ($color === 1) {
//   echo '黒が選ばれました';
// } elseif ($color === 2) {
//   echo 'しろが選ばれました';
// } elseif ($color === 3) {
//   echo '赤が選ばれました';
// }

// switch構文
switch ($color) {
  case 1:
    echo '黒が選ばれました';
    break;
  case 2:
    echo 'しろが選ばれました';
    break;
  case 3:
    echo '赤が選ばべれました';
    break;
}

配列

<?php
// $black = '黒';
// $white = 'しろ';
// $red = '赤';

// $color[0] = '黒';
// $color[1] = 'しろ';
// $color[2] = '赤';

// 配列
$color = ['黒', 'しろ', '赤'];
// $color = array('黒', 'しろ', '赤'); // PHP5以前の書き方

$number = 10;

$myfavorite = 2;
echo $color[$myfavorite];

多次元配列

<?php
// $book[0][0] = 'デザイン入門';
// $book[0][1] = 'デザインの基礎';

// $book[1][0] = 'PHP入門';
// $book[1][1] = '高度なPHP開発';
// $book[1][2] = 'Laravel入門';

// $book[2][0] = 'JavaScript入門';

$book = [
  ['デザイン入門', 'デザインの基礎'],
  ['PHP入門', '高度なPHP開発']
];

// echo $book[0][1];


// print_r 指定した変数に関する情報をわかりやすく出力する
print_r($book);

連想配列

<?php
// $pref['hokkaidou'] = '北海道';
// $pref['aomori'] = '青森県';
// $pref['iwate'] = '岩手県';

// 連想配列はindexとなるキーを設定し、関連する値を代入する
// $pref = [
//   'hokkaido' => '北海道',
//   'aomori' => '青森県',
//   'iwate' => '岩手県'
// ];

// 連想配列の中に配列を入れる
$pref['hokkaido'] = [
  '赤平市',
  '旭川市',
  '芦別市'
];
$pref['aomori'] = [
  '青森市',
  '鰺ヶ沢町'
];

echo $pref['aomori'][1];

配列 ファンクション

<?php
$color = ['黒', 'しろ', '赤'];

// count 変数に含まれる全ての要素、あるいはオブジェクトに含まれる何かの数を数える
// count ( Countable|array $value [, int $mode = COUNT_NORMAL ] ) : int
// 返り値 valueに含まれる要素を返す
// $max = count($color); // 3
// echo $color($max-1); // 要素は3のため

// 一つ以上の要素を配列の最初に加える
// array_unshift($color, '緑', '黄'); // 0] => 緑 [1] => 黄 [2] => 黒 [3] => しろ [4] => 赤
// array_push($color, '緑', '黄'); //[0] => 黒 [1] => しろ [2] => 赤 [3] => 緑 [4] => 黄

// 配列の先頭から要素を一つ取り出して消す
$mycolor = array_shift($color); // [0] => しろ [1] => 赤
echo $mycolor;

$mycolor = array_shift($color); // [0] => 赤
echo $mycolor;

// array_pop 配列の最後の要素を取り出し消す
$color = ['黒', 'しろ', '赤'];
$mycolor = array_pop($color); // [0] => 黒 [1] しろ
echo $mycolor;

$mycolor = array_pop($color); // [0] => 黒
echo $mycolor;

print_r($color);

$color = ['黒', 'しろ', '赤'];
$color_string = implode(',', $color);
print($color_string); // 黒,しろ,赤

$color_string = implode(' - ', $color);
print($color_string); // 黒 - しろ - 赤

$newarray = explode(',', $color_string);
print($color_string);

for構文

<?php
$color = ['黒', '白', '赤'];

for ($i=0; $i<count($color); $i++) {
  echo $color[$i], "\n";
}

foreach

<?php
$pref = [
  'hokkaido' => '北海道',
  'aomori' => '青森県',
  'iwate' => '岩手県'
];

// 連想配列の値を取り出す(配列でも取得できる)
foreach ($pref as $pref_name) {
  echo ' ・ ', $pref_name, "\n";
}

// 連想配列の値とキーを取り出す
foreach ($pref as $pref_key => $pref_name) {
  echo ' ・ ', $pref_key, ':', $pref_name, "\n";
}

while構文

<?php
$q1 = 5;
$q2 = 10;

echo $q1, '+', $q2, 'は? >';
$answer = (int)trim(fgets(STDIN));

while ($answer !== $q1+$q2) {
  echo 'はずれ。もう一回 >';
  $answer = (int)trim(fgets(STDIN));
}
echo 'あたり!';

do while

<?php
// rand 乱数を生成する
// rand ( int $min, int $max ) : int
// $dice = rand(1, 6);

// while ($dice !== 1) {
//   echo $dice, "\n";
//   $dice = rand(1, 6);
// }
// echo $dice;

do {
  $dice = rand(1, 6);
  echo $dice, "\n";
} while ($dice !== 1);

関数

<?php
// $pref = [
//   'hokkaido' => '北海道',
//   'aomori' => '青森県',
//   'iwate' => '岩手県'
// ];

// foreach ($pref as $pref_code => $pref_name) {
//   echo '・', $pref_code, ':', $pref_name, "\n";
// }

// $color = [
//   'red' => '赤',
//   'blue' => '青',
//   'black' => '黒'
// ];

// // 上記と同じことをしている
// foreach ($color as $color_code => $color_name) {
//   echo '・', $color_code, ':', $color_name, "\n";
// }


// ⬇︎⬇︎ 関数を使うと...

// 連想配列を受け取って、リストにして出力する
function make_list($list) {
  foreach ($list as $key => $value) {
    echo '・', $key, ':', $value, "\n";
  }
}

$pref = [
  'hokkaido' => '北海道',
  'aomori' => '青森県',
  'iwate' => '岩手県'
];

make_list($pref);

$color = [
  'red' => '赤',
  'blue' => '青',
  'black' => '黒'
];

make_list($color);

返り値

<?php
// // number_format numberをフォーマットした結果を返す
// $price = number_format(1000);

// echo $price;

function sum($num1, $num2) {
  $answer = $num1 + $num2;

  // return 後の処理は行われない
  return $answer;
}

$item_sum = sum(167, 269);
echo $item_sum;

可変パラメータ

<?php
// // 合計を計算する
// function sum($num1, $num2, $num3) {
//   $answer = $num1 + $num2 + $num3;
//   return $answer;
// }

// $item_sum = sum(10, 20, 30);
// echo $item_sum;

// ⬇︎⬇︎ さらに出力する値を増やしたい場合(可変パラメータの後にパラメータを追加することはできない、パラメータは最後に追加すると使用できる)
function sum(...$numbers) {
  $answer = 0;
  foreach ($numbers as $num) {
    $answer += $num;
  }
  return $answer;
}

$item_sum = sum(10, 20, 30, 40, 50, 60, 70, 80, 90, 100);
echo $item_sum;

可変パラメータのデフォルト引数

<?php
// リストを作る
function make_list($list, $head = '・') {
  foreach($list as $key => $val) {
    echo $head, $key, ':', $val, "\n";
  }
}

$pref = [
  'hokakid' => '北海道',
  'aomori' => '青森県',
  'iwate' => '岩手県'
];

make_list($pref);
// ・hokakid:北海道
// ・aomori:青森県
// ・iwate:岩手県
make_list($pref, '→');
// →hokakid:北海道
// →aomori:青森県
// →iwate:岩手県

リファレンス(参照)渡し

<?php
// $color = ['黒', '赤', '白'];
// リファレンス(参照)渡し
// array_shift($color);
// print_r($color);
// 黒がなくなる
// Array
// (
//     [0] => 赤
//     [1] => 白
// )

// $price = 10000;
// // 値渡し
// // number_formatファンクションの返り値を受け取った変数($new_price)
// $new_price = number_format($price);
// echo $price;
// echo "\n";
// echo $new_price;

// 配列の先頭に文字を繋げる
function add_head(&$target){
  for ($i=0; $i<count($target); $i++) {
    $target[$i] = '●' . $target[$i];
  }
}

$color = ['黒', '赤', '白'];
print_r($color);
// Array
// (
//     [0] => 黒
//     [1] => 赤
//     [2] => 白
// )
add_head($color);
print_r($color);
// Array
// (
//     [0] => ●黒
//     [1] => ●赤
//     [2] => ●白
// )

無名関数(クロージャー)

<?php
// function sum(int $a, int $b): int {
//   return $a + $b;
// }

// 数字を整形して表示する
function echo_price($callback) {
  echo number_format($callback(1000, 500)), '円';
}

// クロージャー・無名関数
// $get_sum = function ($a, $b) {
//   return $a + $b;
// };

$get_sum = fn($a, $b) => $a + $b;

// $sum = $get_sum(10, 15);
// echo_price($get_sum);
echo_price(function($a, $b){
  return $a + $b;
});

オブジェクト指向

<?php
class Item {
  // プロパティ
  public string $name; // 商品名
  public int $price; // 価格

  // メソッドの定義
  public function getPrice(string $end = '') {
    return number_format($this->price) . $end;
  }
}

// Itemクラスからphp_basicインスタンスの生成
$php_basic = new Item();
$php_basic->name = "PHP入門";
$php_basic->price = 15000000;

echo $php_basic->name, '/', $php_basic->getPrice('円');

$js_basic = new Item();
$js_basic->name = 'JS入門';
$js_basic->price = 2300;

コンストラクター

<?php
class Item {
  // プロパティ
  public string $name; // 商品名
  public int $price; // 価格

  // コンストラクター
  public function __construct(string $name, int $price = 0) {
    $this->name = $name;
    $this->price = $price;
  }

  // メソッドの定義
  public function getPrice(string $end = '') {
    return number_format($this->price) . $end;
  }
}

// デフォルト引数が設定されているため第二引数をしてしなくても実行可能
$php_basic = new Item('PHP入門');
echo $php_basic->name, '/', $php_basic->getPrice('円');

$js_basic = new Item('JS入門', 2300);

継承

<?php
class Item {
  // プロパティ
  public string $name; // 商品名
  private int $price; // 価格
  // public int $page; // ページ数

  // コンストラクター
  public function __construct(string $name, int $price = 0) {
    $this->name = $name;
    $this->price = $price;
  }

  // 価格を設定する
  public function setPrice(int $price) {
    if ($price < 0) {
      return false;
    }
    $this->price = $price;
    return true;
  }

  // 価格を取得する
  public function getPrice(string $end = '') {
    return number_format($this->price) . $end;
  }
}

// Itemクラスを継承
class Book extends Item {
  public int $page; // 書籍のページ数
}

$php_basic = new Book('PHP入門', 2300);
$php_basic->page = 100;
$php_basic->setPrice(1500);

echo $php_basic->name, '(', $php_basic->page, 'ページ/', $php_basic->getPrice('円');

$js_basic = new Item('JS入門', 2300);

メソッドのオーバーライド

<?php
class Item {
  // protected 親クラスと継承したクラスで参照できるプロパティ
  protected int $uint; // 個数(アクセス修飾子をprivateにすると継承クラスでは使用できない)

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

  public function getUint(): string {
    return $this->uint . '個';
  }
}

class Book extends Item {
  // オーバーライド(親クラスで定義されたメソッドを上書きする)
  public function getUint(): string {
    return $this->uint . '冊';
  }
}

$eraser = new Item(10);
echo $eraser->getUint(), "\n"; // 10個

$book = new Book(5);
echo $book->getUint(); // 5冊

親クラスのメソッド呼び出し parent::

<?php
class Item {
  // protected 親クラスと継承したクラスで参照できるプロパティ
  protected int $unit; // 個数(アクセス修飾子をprivateにすると継承クラスでは使用できない)

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

  public function getUnit(): string {
    return $this->unit . '個';
  }
}

class Book extends Item {
  private int $page; // ページ数
  public function __construct(int $unit, int $page) {
    // parent:: 自分の親クラス
    parent::__construct($unit);
    $this->page = $page;
  }
  // オーバーライド(親クラスで定義されたメソッドを上書きする)
  public function getUnit(): string {
    return $this->unit . '冊';
  }
}

$eraser = new Item(10);
echo $eraser->getUnit(), "\n";

$book = new Book(5, 120);
echo $book->getUnit();

インターフェイス

<?php
// 今回であればgetPriceメソッドを必ず使用しなければならない
interface ItemInterface {
  public function getPrice(): int;
}

// ItemInterfaceを実装したBookクラス
class Book implements ItemInterface {
  private int $price;
  public function getPrice(): int {
    return $this->price;
  }
}

// ItemInterfaceを実装したPencilクラス
class Pencil implements ItemInterface {
  private int $price;
  public function getPrice(): int {
    return $this->price;
  }
}

抽象クラス

インターフェイスと同様、約束事を定義できるが
通常のクラスと同じようにプロパティやメソッドを定義できる

<?php
// 抽象クラス
abstract class Item {
  private $price;

  public function getPrice() {
    return $this->price;
  }

  // 抽象メソッド
  abstract public function getUnit();
}

class Book extends Item {
  public function getUnit() {
    return '冊';
  }
}

class Pen extends Item {
  public function getUnit() {
    return '本';
  }
}

$book = new Book();
$book->getPrice();

トレイト

再利用可能なもの

<?php
trait Tax {
  // 消費税を返す
  public function getTax(): int {
    return 10;
  }
}

// 外国の消費税を扱う
trait ForeignTax {
  public function getTax(): int {
    return 20;
  }
}

class Item {
  // TaxとForeginTax2つのトレイトを使用(同じメソッド名の場合)
  use Tax, ForeignTax {
    Tax::getTax insteadof ForeignTax;
    ForeignTax::getTax as getForeginTax;
  }
  private int $price;
}

class Service {
  use Tax;
  private int $service_price;
}

$item = new Item;
echo $item->getTax(), "\n";
echo $item->getForeginTax(), "\n";

$service = new Service;
echo $service->getTax(), "\n";

名前空間

<?php
require_once 'app/Shop/Book.php';
require_once 'app/Review/Book.php';

// path\to\クラス名;
use app\Shop\Book;
use app\Review\Book as BookReview;

$book = new Book();
echo $book->getPrice(), "\n";

$book_review = new BookReview();
echo $book_review->getPoint(), "\n";

静的プロパティ・静的メソッド

<?php
class Item {
  // 静的プロパティ
  public static int $tax = 10; // 消費税

  // 静的メソッド
  public static function getTax(): int {
    // 静的メソッドから静的プロパティを呼び出す際はselfを使用する
    return self::$tax;
  }

  // // 静的メソッド内では$thisは使用できない
  // public static function getTax(): int {
  //   return 15;
  // }
}

// $item = new Item();
// echo $item->getTax();

// echo Item::getTax();

echo Item::$tax;
Item::$tax = 8;

$item02 = new Item();
echo $item02->getTax();

インスタンスの複製(clone)

<?php
class Item {
  public string $name;
}

$item01 = new Item();
$item01->name = 'PHP入門';

// 参照渡し
$item02 = $item01;

// 値渡し
$item02 = clone($item01);

$item01->name = 'JS入門';
echo $item02->name;

React Hooks あれこれ

環境構築

npx create-react-app --scripts-version バージョン アプリ名

バージョン確認方法

npm info create-react-app

構築できたか確認(自動で立ち上がる)

yarn start

基本

import React, { useState } from 'react';
const [count, setCount] = useState(0)

常に2つの要素を返すため、Javascriptの分割代入を使用してそれぞれの要素を受け取る
1つ目の要素(count)は今回であれば0(useStateの状態)が返ってくる
2つ目の要素(setCount)は関数(function)
関数にも名前をつける(キャメルケース)

import React, { useState } from 'react';


const App = () => {
  const [count, setCount] = useState(0)

  const increment = () => setCount(count + 1)
  const decrement = () => setCount(count - 1)

  return (
    <>
      <div>count: {count}</div>
      <button onClick={increment}>+1</button>
      <button onClick={decrement}>-1</button>
    </>
  );
}

export default App;
<button onClick={increment}>+1</button>

onClickでボタンがクリックされたらイベント発火
今回であればincrement関数が呼び出される

 const increment = () => setCount(count + 1)

今回であれば、状態countを+1したい
このcountを変更させるには、setCountに値を与えることでcountの状態が変更される

setCountの引数に値ではなく、関数を渡すこともできる
関数に状態を変えさせることもできる
引数には現時点での状態を返す
その値をもとに状態を変更したい場合に使用する

import React, { useState } from 'react';

const App = () => {
  const [count, setCount] = useState(0)

  const increment = () => setCount(count + 1)
  const decrement = () => setCount(count - 1)

  const increment2 = () => setCount(previousCount => previousCount + 1)
  const decrement2 = () => setCount(previousCount => previousCount - 1)

  const reset = () => setCount(0)
  const dobule = () => setCount(count * 2)
  const divide3 = () => setCount(previousCount =>
    previousCount % 3 === 0 ? previousCount / 3 : previousCount
  )

  return (
    <>
      <div>count: {count}</div>
      <div>
        <button onClick={increment}>+1</button>
        <button onClick={decrement}>-1</button>
      </div>
      <div>
        <button onClick={increment2}>+1</button>
        <button onClick={decrement2}>-1</button>
      </div>
      <div>
        <button onClick={reset}>Reset</button>
        <button onClick={dobule}>×2</button>
        <button onClick={divide3}>3の倍数の時だけ3で割る</button>
      </div>
    </>
  );
}

export default App;

複数の状態管理

import React, { useState } from 'react';

const App = props => {
  const [name, setName] = useState(props.name)
  const [price, setPrice] = useState(props.price)

  const reset = () => {
    setPrice(props.price)
    setName(props.name)
  }

  return (
    <>
      <p>現在の{name}は、{price}円です。</p>
      <button onClick={() => setPrice(price + 1)}>+1</button>
      <button onClick={() => setPrice(price - 1)}>-1</button>
      <button onClick={reset}>Reset</button>
      <input value={name} onChange={e => setName(e.target.value)}/>
    </>
  );
}

App.defaultProps = {
  name: '',
  price: 1000
}

export default App;
<input value={name} onChange={e => setName(e.target.value)}/>

onChangeでイベントを拾う(e)
e.target.valueでinputに入力された文字列を拾う

複数の状態を1つのオブジェクトに統合

import React, { useState } from 'react';

const App = props => {
  const [state, setState] = useState(props)
  const { name, price } = state

  return (
    <>
      <p>現在の{name}は、{price}円です。</p>
      <button onClick={() => setState({...state, price: price + 1})}>+1</button>
      <button onClick={() => setState({...state, price: price - 1})}>-1</button>
      <button onClick={() => setState(props)}>Reset</button>
      <input value={name} onChange={e => setState({...state, name: e.target.value})}/>
    </>
  );
}

App.defaultProps = {
  name: '',
  price: 1000
}

export default App;

useEffect

// useEffectをimportする
import React, { useEffect, useState } from 'react';

// 第一引数に関数を引き取ることができる
// jsxのrenderingの後にuseEffectは実行される(Domのどこかの要素に変更があれば呼び出される)
useEffect(() => {
    console.log('This is like componentDidMount or componentDidUpdate.')
  })

// 最初のrenderingのみ呼び出すには第二引数に空の配列を持たす
  useEffect(() => {
    console.log('This is like componentDidMount')
  }, [])

// 特定のパラメータの描画時または変更時のみ呼び出す時(今回であればnameが描画された時または変更された時に呼び出す)
  useEffect(() => {
    console.log('This callback is for name only.')
  }, [name])

reducer

const events = (state = [], action) => {
  switch (action.type){
    case 'CREATE_EVENT':
      const event = { title: action.title, body: action.body }
      const length = state.length
      const id = length === 0 ? 1 : state[length -1].id + 1
      return [...state, { id, ...event }]
    case 'DELETE_EVENT':
    case 'DELETE_ALL_EVENTS':
      return []
    default:
      return state
  }
}

export default events
const events = (state = [], action) => {}

reducerは2つの引数を受け取る 1つ目はstate(前回の状態)を受け取る 2つ目はactionを受け取る stateは未定義の場合があるため、state = []で初期化しておく

switch (action.type){
    case 'CREATE_EVENT':
      // データを吸い上げる
      const event = { title: action.title, body: action.body }
      // stateの長さを把握する
      const length = state.length
      // stateの長さが0であれば1を返す、0でなければ最後のidに+1をして返す
      const id = length === 0 ? 1 : state[length -1].id + 1
      // stateの最後の要素にeventデータを格納する
      return [...state, { id, ...event }]
    case 'DELETE_EVENT':
    case 'DELETE_ALL_EVENTS':
      return []
    default:
      return state
}

actionは常にtypeという属性が渡ってくる 今回であれば、typeは作成する場合、削除される場合、そういったtype以外の場合でswitchさせる

React Firebase 連携

構築

npx create-react-app . --template typescript
npm start

立ち上がっていればOK

必要なライブラリをインストール

npm i @material-ui/core
npm i @material-ui/icons
npm i firebase
npm i react-router-dom @types/react-router-dom
npm start

型をインストールする

yarn add -D @types/react

※reactは typescriptで書かれてない上、
型提供も元パッケージでしていないので型を別でインストールする必要がある

-Dオプション
devDependencies:開発用の依存関係

アローファンクションのテンプレートを使用できる

rafce

Firebaseとの連携

.envファイルに環境変数を設定する

REACT_APP_FIREBASE_APIKEY=""
REACT_APP_FIREBASE_DOMAIN=""
REACT_APP_FIREBASE_DATABASE=""
REACT_APP_FIREBASE_PROJECT_ID=""
REACT_APP_FIREBASE_STORAGE_BUCKET=""
REACT_APP_FIREBASE_SENDER_ID=""
REACT_APP_FIREBASE_APP_ID=""

firebase.tsを作成する

import firebase from "firebase/app";
import "firebase/app";
import "firebase/firestore";
import "firebase/auth";

const firebaseApp = firebase.initializeApp({
  apiKey: process.env.REACT_APP_FIREBASE_APIKEY,
  authDomain: process.env.REACT_APP_FIREBASE_DOMAIN,
  databaseURL: process.env.REACT_APP_FIREBASE_DATABASE,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
  messageingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID,
  appId: process.env.REACT_APP_FIREBASE_APP_ID,
});

export const db = firebaseApp.firestore();
export const auth = firebase.auth();

Firebaseにてデータベースを作成する
 コレクションを開始
 ドキュメントIDを自動生成
 フィールド入力(titleなど)
 タイプを指定(stringなど)
 値を入力(任意)

React側で取得する

import { List } from "@material-ui/core";
import React,{useState, useEffect} from 'react';
import './App.css';
import { db } from "./firebase";

const App: React.FC = () => {
  const [tasks, setTasks] = useState([{id:"", title:""}]);
  useEffect(()=> {
    const unSub = db.collection("tasks").onSnapshot((snapshot)=>{
      setTasks(
        snapshot.docs.map((doc)=> ({id: doc.id, title: doc.data().title}))
      );
    });
    return ()=> unSub();
  },[]);

  return (
    <div className="App">
      {tasks.map((task) => (
        <h3>{task.title}</h3>
      ))}
    </div>
  );
};

export default App;

firebaseから取得したtasksの内容をReact側でstateとして保持しておきたいためuseStateを使用する

// 空の内容で初期化
const [tasks, setTasks] = useState([{id:"", title:""}]);

アプリケーションが立ち上がった時にfirebaseへアクセスして
存在するデータベースのtasksの内容を取得するためuseEffectを使用する
アプリケーションが起動した最初の1回のみデータを読みに行きたいため
第二引数は空にする

useEffect(()=> {},[]);

実際にデータベースへアクセスする内容
db.collectionで取得したいデータベース名を指定する
onSnapshotでデータベースの内容を取得する
firestoreから取得した内容を(snapshot)の引数にいれて実際の処理を行う
取得したtasksのオブジェクトの一覧をsetTasksを使ってtasksのstateに格納する
snapshotの複数あるdocumentをmapで展開する

  useEffect(()=> {
    const unSub = db.collection("tasks").onSnapshot((snapshot)=>{
      setTasks(
        snapshot.docs.map((doc)=> ({id: doc.id, title: doc.data().title}))
      );
    });
    return ()=> unSub();
  },[]);

取得した内容をブラウザへ表示する

const App: React.FC = () => {
  const [tasks, setTasks] = useState([{id:"", title:""}]);
  useEffect(()=> {
    const unSub = db.collection("tasks").onSnapshot((snapshot)=>{
      setTasks(
        snapshot.docs.map((doc)=> ({id: doc.id, title: doc.data().title}))
      );
    });
    return ()=> unSub();
  },[]);

  return (
    <div className="App">
      {tasks.map((task) => (
        <h3 key={task.id}>{task.title}</h3>
      ))}
    </div>
  );
};

タスクを作る

import { FormControl, TextField } from "@material-ui/core";
import React,{useState, useEffect} from 'react';
import './App.css';
import { db } from "./firebase";
import AddToPhotosIcon from "@material-ui/icons/AddToPhotos";

const App: React.FC = () => {
  const [tasks, setTasks] = useState([{id:"", title:""}]);
  const [input, setInput] = useState("");

  useEffect(()=> {
    const unSub = db.collection("tasks").onSnapshot((snapshot)=>{
      setTasks(
        snapshot.docs.map((doc)=> ({id: doc.id, title: doc.data().title}))
      );
    });
    return ()=> unSub();
  },[]);

  const newTask = (e: React.MouseEvent<HTMLButtonElement>)=>{
    db.collection("tasks").add({title: input});
    setInput("");
  }

  return (
    <div className="App">
      <h1>Todo App by React/Firebase</h1>
      <FormControl>
        <TextField
        InputLabelProps={{
          shrink: true,
        }}
        label="New task ?"
        value={input}
        onChange={(e: React.ChangeEvent<HTMLInputElement>) => setInput(e.target.value)}
        />
      </FormControl>
      <button disabled={!input} onClick={newTask}>
        <AddToPhotosIcon />
      </button>
      {tasks.map((task) => (
        <h3 key={task.id}>{task.title}</h3>
      ))}
    </div>
  );
};

export default App;

ユーザーがタイピングした文字列を保持するためのstateをuseStateを使用して実行する

// 初期値を空にセット
const [input, setInput] = useState("");

material-uiを使用してフォームを作成する

import { FormControl, TextField } from "@material-ui/core";

<FormControl>
    <TextField
      InputLabelProps={{
        shrink: true,
      }}
      label="New task ?"
      value={input}
      // ユーザーがタイピングするために呼び出される関数を定義
      // input stateの内容を上書きするためsetInputを毎回呼び出す(ユーザーがタイピングしたvalueの値を取得している)
      // typescriptではイベントオブジェクトに型を指定する必要がある
      onChange={(e: React.ChangeEvent<HTMLInputElement>) => setInput(e.target.value)}
    />
</FormControl>

送信用のボタンを作成する

import AddToPhotosIcon from "@material-ui/icons/AddToPhotos";

      // 入力フォームが空の時はボタンを押せない
      // ボタンが押された時に呼び出される関数(newTask)を指定する
      <button disabled={!input} onClick={newTask}>
        <AddToPhotosIcon />
      </button>

ボタンを押した時の呼び出される関数を作成

  const newTask = (e: React.MouseEvent<HTMLButtonElement>)=>{
    // firebaseのデータベースにタスクを追加するため、db.collectionで追加したいコレクションを指定する(addでオブジェクトを渡す)
    db.collection("tasks").add({title: input});
    // 次の新しいタスクの作成に備えてinput stateを初期化しておく
    setInput("");
  }

※onClickなどのデータ型を知りたい場合は、onClickにカーソルを合わせると表示される

JavaScript基礎

JavaScriptとは

主にWebブラウザ上の中で動くプログラミング言語
また、Webブラウザだけでなく、Node.jsというサーバ側のアプリケーションを作る仕組みでも利用されている

JavaScriptECMAScriptという仕様によって動作が決められている
ECMAScriptという仕様ではどの実行環境でも共通な動作のみが定義されているため、基本的にどの実行環境でも同じ動作をする

JavaScriptの特徴

元々、Netscape Navigatorというブラウザのために開発されたプログラミング言語
C、Java、Self、Schemeなどのプログラミング言語の影響を受けて作られた

大部分がオブジェクトであり、そのオブジェクト同士のコミュニケーションによって成り立っている
オブジェクトには、ECMAScriptのしようとして定められたオブジェクト、実行環境が定義したオブジェクト、ユーザーの定義したオブジェクトが存在する

●大文字と小文字を区別する
予約語を持つ
●文はセミコロンで区切られる
●strict mode(古く安全でない構文や機能が一部禁止される、use strictという文字列をファイルまたは関数の先頭に書く)

構文

コメント

// 一行コメント

/**
 * 複数行コメント
 */

変数と宣言

const、let、varの3つがある
varはもっとも古くからある変数宣言のキーワードで意図しない動作を作りやすい問題からECMAScript2015で、varの問題を改善するためにconstとletという新しいキーワードが導入された

// constは再代入できない変数を宣言するキーワード
const bookTitle = "JavaScript";
bookTitle = "New";  // => TypeError: invalid assignment to const 'bookTitle'

// constは定数ではない
const object = {
  key: "New"
};
// オブジェクトそのものは変更できる
object.key = "New2";


// letは値の再代入が可能な変数を宣言できる
let bookTitle = "Javascript";

// letはconstと異なり初期値を指定しない変数も定義できる
let bookTitle;  // => undefinedという値になる

データ型

JavaScriptは動的型付け言語に分類される言語であるため、静的型付け言語のような変数の型はない
文字列、数値、真偽値といった値の型は存在する
これらの値の型のことをデータ型と呼ぶ

データ型には2種類存在する
1、プリミティブ型(基本型)
2、オブジェクト(複合型)

●プリミティブ型(基本型)
 プリミティブ型(基本型)は、真偽値や数値などの基本的な値の型のこと
 プリミティブ型の値は、一度作成したらその値自体を変更できないというイミュータブル(immutable)の特性を持つ
  真偽値(Boolean): trueまたはfalseのデータ型
  数値(Number): 42 や 3.14159 などの数値のデータ型
  巨大な整数(BigInt): ES2020から追加された9007199254740992nなどの任意精度の整数のデータ型
  文字列(String): "JavaScript" などの文字列のデータ型
  undefined: 値が未定義であることを意味するデータ型
  null: 値が存在しないことを意味するデータ型
  シンボル(Symbol): ES2015から追加された一意で不変な値のデータ型

●オブジェクト(複合型)
 オブジェクトは複数のプリミティブ型の値またはオブジェクトからなる集合
 オブジェクトは、一度作成した後もその値自体を変更できるためミュータブル(mutable)の特性を持つ
 
 ・プリミティブ型以外のデータ
  オブジェクト、配列、関数、正規表現、Dateなど
// typeof演算子でデータ型を調べることができる
console.log(typeof true);  // => boolean

リテラル

プリミティブ型の値や一部のオブジェクトはリテラルを使うことで簡単に定義できるようになっている
リテラルとはプログラム上で数値や文字列など、データ型の値を直接記述できるように構文として定義されたもの

// " と " で囲んだ範囲が文字列リテラル
const str = "Hello";

リテラル表現がない場合はその値を作る関数に引数を渡して作成する形になる
そのような冗長な表現を避ける方法としてよく利用される主要な値にはリテラルが用意されている

ダブルクォートとシングルクォート

// \' のように \(バックスラッシュ)を使いエスケープしなければならない
"8 o\'clock";  //  => "8 o'clock"

オブジェクトリテラル

// オブジェクトリテラルは{}を書くことで新しいオブジェクトを作成できる
const obj = {};  // 中身がからのオブジェクトを作成

// keyというキー名とvalueという値を持つオブジェクトを作成
const obj = {
  "key": "value"  // オブジェクトが持つキーのことをプロパティと呼ぶ。この場合、objというオブジェクトはkeyというプロパティを持っている
};

// ドット記法
console.log(obj.key); // => value

// ブラケット記法
console.log(obj["key"]); // => value

配列リテラル

// [ と ]で値をカンマ区切りで囲み、その値を持つArrayオブジェクトを作成
const emptyArray = [];  // 空の配列を作成
const array = [1, 2, 3];  // 値を持った配列を作成

正規表現リテラル

// 数値にマッチする特殊文字である\dを使い、1文字以上の数字にマッチする正規表現
const numberRegExp = /\d+/;

// numberRegExpの正規表現が文字列"123"にマッチするかをテスト
console.log(numberRegExp.test("123")); // => true

関数と宣言

// 仮引数に対応する引数が渡されていない場合に、デフォルトで代入される値を指定できる
function echo(x = "デフォルト値") {
    return x;
}

console.log(echo(1)); // => 1
console.log(echo()); // => "デフォルト値"

可変長引数

// Math.maxは可変長引数を受け取る関数で、受け取った引数の中で最大の数値を返す関数
const max = Math.max(1, 5, 10, 20);
console.log(max); // => 20

Rest parameters

Rest parametersは、仮引数名の前に...をつけた仮引数のことで、残余引数とも呼ばれる
Rest parametersには、関数に渡された値が配列として代入される

function fn(...args) {
    // argsは引数の値が順番に入った配列
    console.log(args); // => ["a", "b", "c"]
}
fn("a", "b", "c");

Arrow Function

// Arrow Functionを使った関数定義
const 関数名 = () => {
    // 関数を呼び出したときの処理
    // ...
    return 関数の返す値;
};

// 仮引数の数と定義
const fnA = () => { /* 仮引数がないとき */ };
const fnB = (x) => { /* 仮引数が1つのみのとき */ };
const fnC = x => { /* 仮引数が1つのみのときは()を省略可能 */ };
const fnD = (x, y) => { /* 仮引数が複数のとき */ };
// 値の返し方
// 次の2つの定義は同じ意味となる
const mulA = x => { return x * x; }; // ブロックの中でreturn
const mulB = x => x * x;            // 1行のみの場合はreturnとブロックを省略できる

コールバック関数

関数はファーストクラスであるため、その場で作った匿名関数を関数の引数(値)として渡すことができる 引数として渡される関数のことをコールバック関数と呼ぶ 一方、コールバック関数を引数として使う関数やメソッドのことを高階関数と呼ぶ

function 高階関数(コールバック関数) {
    コールバック関数();
}

const array = [1, 2, 3];
array.forEach((value) => {
    console.log(value);
});
// 1 2 3

メソッド

const obj = {
    method1: function() {
        // `function`キーワードでのメソッド
    },
    method2: () => {
        // Arrow Functionでのメソッド
    }
};

const obj = {
    method: function() {
        return "this is method";
    }
};
console.log(obj.method()); // => "this is method"

// メソッドの短縮記法
const obj = {
    method() {
        return "this is method";
    }
};
console.log(obj.method()); // => "this is method"
/**
 * const, letなどの変数宣言
 */
// var val1 = "var変数";
// console.log(val1);

// // var変数は上書き可能
// val1 = "var変数を上書き";
// console.log(val1);

// // var変数は再宣言可能
// var val1 = "var変数を再宣言";
// console.log(val1);

// let val2 = "let変数";
// console.log(val2);

// // letは上書きが可能
// val2 = "let変数を上書き";
// console.log(val2);

// // letは再宣言不可能
// let val2 = "let変数を再宣言";

// const val3 = "const変数";
// console.log(val3);

// // const変数は上書き不可
// val3 = "const変数を上書き";

// const val3 = "const変数を再宣言";

// constで定義したオブジェクトはプロパティの変更が可能
const val4 = {
  name: "test",
  age: 28,
};
val4.name = "taro";
val4.address = "JAPAN";
console.log(val4);

// constで定義した配列はプロパティの変更が可能
const val5 = ['dog', 'cat'];
val5[0] = "bird";
val5.push("monkey");
console.log(val5);

AWS メモ

インスタンスメタデータ
 実行中のインスタンスを構成または管理するために
 使用できるインスタンスに関するデータ

 インスタンスメタデータは、ホスト名・イベント
 及びセキュリティグループなどのカテゴリに割り当てられる

 これを利用してインスタンスの構成情報などの基本情報を
 取得するなどできるため自動化プロセス設定には利用されない


●T3インスタンス

 ベースラインレベルのCPUパフォーマンスを提供する
 次世代のバースト可能な汎用インスタンスタイプで
 いつでも必要な時間だけCPU利用率をバーストさせることが可能

 T3インスタンスはバランスのとれたコンピューティング、
 メモリ及びネットワークのリソースを提供し、
 使用中に一時的なスパイクが生じる中程度の
 CPU使用率を持つアプリケーション向けに設計されている


●G4インスタンス

 業界内で最も費用対効果の高いGPUインスタンス

 機械学習モデルの本番環境へのデプロイや
 グラフィックスを多用するアプリケーションに適している

 高機能だがT2及びT3インスタンスよりも高価なため
 コスト最適なインスタンスではなく、
 また機械学習やゲーミングで利用するインスタンスタイプである


●A1インスタンス

 包括的なArmエコシステムによりサポートされる
 スケールアウト型のArmベースのワークロードに
 最適で大幅なコスト削減を実現できる

 A1インスタンスAWS Gravitonプロセッサで
 動作する初のEC2インスタンス

 このプロセッサには64ビットのArm Neoverseコアと
 AWSが設計したカスタムシリコンタイプでありコスト最適化ではない


●M5インスタンス

 Intel Xeon_Platinum 8175Mプロセッサを搭載した
 最新世代の汎用インスタンス

 このファミリーはバランスのとれたコンピューティング、
 メモリ、及びネットワークのリソースを提供し多くのアプリケーションに適している

 T2及びT3インスタンスと異なり、バースト性能がないため
 CPU使用率の上昇に対しても一定のパフォーマンスを
 保証できるインスタンスタイプという要件には合致しない


AWS Artifact

 AWSとの契約やコンプライアンスなどに関わる情報を
 一元管理することができるサービス

 ユーザーとの契約にかかる文章のほか、
 AWS独自のコンプライアンス対応に関するレポートが提供される

 AWS Artifactでは、AWSのセキュリティ及び
 コンプライアンスレポートと特定のオンライン契約にオンデマンドでアクセスできる

 Service Organization Control(SOC)、Payment Card Industry(PCI)レポート、
 AWSセキュリティ制御の実装と運用の有効性を検証する
 様々な地域やコンプライアンス垂直市場の認定機関からの認定が含まれる

 事業提携契約(BAA)と機密保持契約(NDA)を管理することができる

 AWSコンプライアンスレポートへの
 オンデマンドアクセス用のセルフサービスポータルである
 AWS Artificatを使用することにより
 PCI DSSコンプライアンス証明(AOC)及び責任概要を利用できる


AWS Config

 AWSリソースの認定を評価・監査・審査できるサービス

 ConfigにはAWSリソースの設定が継続的にモニタリング及び記録され、
 望まれる設定に対する評価を自動的に実行できる

 Payment Card Industry(PCI)レポートに基づいた情報提供はされない


Amazon Macie

 機械学習を使用しAWSの機密データを自動的に検出、
 分類、保護するセキュリティサービス


●SpilloverCount

 ELB上でEC2インスタンスにルーティングされている
 HTTPリスナーとTCPリスナーのリクエスト失敗状況を確認できる


●RequestCount

 指定された間隔(1分または5分)の間に完了した
 リクエスト数、または接続の数を取得する

 完了したリクエストでは失敗状況の判断はできない


●UnHealthyHostCount

 ロードバランサーに登録された異常なインスタンス数を取得する
 インスタンスはヘルスチェックに対して構成された
 異常な閾値を超えると異常な状態とみなしてくれる
 異常なインスタンスはヘルスチェックに設定されている状態の
 閾値を満たせば再び正常な状態とみなされる
 ヘルスチェック結果としての異常なインスタンスを検知することができるが、
 リクエストの失敗状況に関する情報を取得することができない


●SurgeQueueLength

 異常なインスタンスへのルーティングを
 保留中のリクエスト(HTTPリスナー)または接続(TCPリスナー)の合計数


AWS Systems Manager Automation

 EC2インスタンス及び他のAWSリソースの
 一般的なメンテナンスとデプロイに関する運用タスクを自動化することが可能

 その際に自動化ワークフローを構築しインスタンス及びAWSリソースを設定する

 独自のカスタムワークフローを作成するかAWSの定義済みのワークフローを使用することが可能


●IDS / IPS

 不正侵入検知(IDS)、不正侵入制御(IPS)


●Palo Alto Networks

 全てのVPC上にある悪意のあるトラフィック通信を監視、フィルタリングする


AWS Shield Advanced

 アプリケーションを標的とした攻撃に対する高レベルな保護に使用する

 Standard版は高度な保護には不十分


Amazon GuardDuty

 AWSアカウントとワークロードを継続的にモニタリングし、
 悪意のあるアクティビティや不正なアクティビティから保護する


AWS Systems Manager Patch Manager

 セキュリティ関連のアップデート及びその他のタイプのアップデートの両方に関して、
 インスタンスへのパッチ適用プロセスを自動化する

 Patch Managerを使用してオペレーティングシステム
 アプリケーションの両方にパッチを適用することができる

 AWS Systems Manager Patch Managerを使用することで、
 EC2インスタンスのフリート全体のOSのセキュリティパッチの適用を
 スケジューリングして自動実行することが可能となる


AWS Batch

 AWSクラウドでバッチコンピューティングワークロードを実行できる

 OSパッチの管理にはAWS Systems Manager Patch Managerを利用する


●EC2Rescue

 EC2のWindowsインスタンスへの接続に失敗した場合や、
 起動上のトラブルが発生した場合にトラブルの分析に利用するログ収集をなどを実施する


AWS SAM(Serverless Application Model)

 サーバーレスアプリケーション構築用のオープンソースフレームワーク

 Lambda関数などのサーバーレスアプリケーションをデプロイする際に利用される

 その際の実行環境はCloudFormationに依存しており
 CloudFormationテンプレート内にSAMの設定を実施しデプロイを実行する


●AWSTrustedAdvisor

 AWSインフラストラクチャサービスを監視し、既知のベストプラクティスと
 比較し節約やシステムパフォーマンス、セキュリティの観点からチェックをしてくれるプログラム

 これを利用し、ユーザーが利用するAWSリソース構成のセキュリティ対応状況をベストプラクティスと比較してくれる


TCO計算ツール

 AWS移行した際の利用コストを試算することができ、
 オンプレミス環境やその他の費用比較が可能となる

 また、総コスト計算ツールでは、ビジネスニーズを最適に
 満たすように家庭を変更することもできる

 あくまで見積もりツール


AWS Health

 AWSのリソース、サービス、およびアカウントの状態をリアルタイムで可視化する

 このサービスでは、AWSで実行されるアプリケーションに影響を与えている
 リソースのパフォーマンスや可用性の問題の把握と修復のガイダンスを提供する


Amazon CloudSearch

 AWSクラウドで完全に管理された検索サービス

 高速で非常に拡張性の高い検索機能をアプリケーションに容易に統合できる


Amazon Inspector

 EC2インスタンスにおける通信の詳細、安全なチャンネルの使用、
 実行中のプロセスの詳細、実行中のネットワークトラフィックなどのデータを収集して評価レポートを作成することが可能

 自動化されたセキュリティ評価サービスで、AWSにデプロイしたアプリケーションの
 セキュリティとコンプライアンスを向上させることができる

 自動的にアプリケーションを評価し、露出、脆弱性、ベストプラクティスからの逸脱がないかどうかを確認できる

 評価結果は詳細なリストがAmazon Inspectorによって作成される

 この調査結果は直接確認することもできるがAmazon Inspectorコンソール
 またはAPIを介して入手可能な詳細な評価レポートで確認できる


Amazon Cognito

 ウェブアプリケーションおよびモバイルアプリに素早く簡単にユーザーの
 サインアップ/サインインおよびアクセスコントロール機能を追加できる

 Amazon Cognitoは、数百万人のユーザーにスケールし、FacebookGoogle
 AmazonなどのソーシャルIDプロバイダー、およびSAML2.0による
 エンタープライズIDプロバイダーを使用したサインインをサポートする

 フェデレーションIDプロバイダー用の組み込みUIと簡単な設定を使用すれば
 数分でAmazon Cognitoを統合して、アプリケーションにサインイン、
 サインアップ、アクセスコントロール機能を追加できる


AWS Config

 AWSリソースに対してカスタムまたは管理されたルールを評価して通知することができる

 これは、リソースが定義したカスタムルールに準拠していることを確認する場合にも利用できる

 さらに、AWS ConfigにSNSトピックを連携すればSNSを利用した通知設定が可能

 例えば、リソースが更新されるとメール通知が実施され、変更内容が表示できる


●cfn-signalヘルパースクリプト

 AWS CloudFormationに信号を送り、EC2インスタンスが正常に作成魔tは更新されたかどうかを示す

 つまり、cfn-signalヘルパースクリプトの信号を確認し、
 直前のタスクが終了したのを確認した上で、次のリソース設定を始めることが可能となる


AWS::AutoScaling::AutoScalingGroupリソース

 UpdatePolicy属性を使用し、AWS CloudFormationスタックが
 更新されるときのAutoScalingグループリソースの更新方法を定義する

 UpdatePolicy属性が正しく設定されていない場合、ローリング更新によって
 予期しない結果が生成される可能性がある

 AWS CloudFormationがAutoScalingグループのローリング更新を処理する方法は
 AutoScalingRolingUpdateポリシーを使用して制御できる

 この共通的なアプローチでは同じAutoScalingグループを保持し、
 設定したパラメータに基づいて古いインスタンスの置き換えを行う


AWS Systems Managerパラメータストア

 設定データ管理と機密管理のための安全な階層型ストレージを提供する

 パスワード、データベース文字列、ライセンスコードなどの
 データをパラメータ値として保存することができる

 値は、プレーンテキストまたは暗号テキストとして保存できる

 これをCloudFormationテンプレートのパラメーターストアセクションで設定することで
 Systems Managerのパブリックパラメータストアを参照して最新AMIを引っ張ってくることができる

 テンプレートやパラメータなど何も変更せずにCloudFormationスタックを更新するだけで
 リソースの要件に応じてその時点でサイン真のAMIIDに更新される


●set-load-balancer-listener-ssl-certificateコマンド

 証明書を設定する


AWS Server Migration Service(SMS)  数千のオンプレミスワークロードを従来よりも簡単に、かつ短時間でAWSに移行できるエージェントレスサービス  AWS SMSではライブサーバーボリュームの増分レプリケーションの自動化、スケージュール設定、および追跡が可能なため大規模なサーバーの移行作業を簡単に調整できる

●認証情報レポート  IAMユーザーが最後にAWSサービスにアクセスした日付と時刻を表示する機能を提供する  アカウントの全てのユーザーとユーザーの各種認証情報(パスワード、アクセスキー、MFAデバイスなど)のステータスが表示された認証情報レポートを生成する

AWS Picing Calculator  アーキテクチャソリューションのコストを見積もるサービス

●パワーユーザー  管理者権限以外のあらゆるAWSリソースに対する権限を有したユーザーのこと

AWS X-Ray  リクエスト動作の確認、アプリケーションの問題の検出、アプリケーションのパフォーマンスの向上

パーティションプレイスメントグループ  HDFS、HBase、Cassandraなどの大規模な分散および複製ワークロードを行うラック間ででプライスるために使用できる

Oracle RAC(Real Application Clusters)  複数のサーバーで1つのデータベースを構成するOracleクラスタ環境構成  アクティブ・アクティブで構成されるデータベース構成をとるため、サーバリソースを100%活用できることができる  RDS OracleデータベースエンジンではRAC構成を使用することができない


メモ
・ICMP(Internet Control Message Protocol)

・RDP(Remote Desktop Protocol)

AWSでは第三者に一時的なアクセス権限を付与する際は、IAMロールを利用することが推奨されている  IAMユーザーは一時的に利用するものではない

・RDSの自動バックアップを実施すると、S3にスナップショットを取ることでバックアップを迅速に復元しトランザクションログは5分ごとにS3に保存されるため、アプリケーションを15分というRPO以内の状態に復元することが可能

・EFSにはファイルロック機能はあるが、ファイルバージョン管理機能はない

RAID1はRTO1分以内の回復が可能

AWSリソースの更新状況を保持しておくサービスはAWS Config、CloudTrailはAWSリソースの更新状況は保持できない

・ELBにCloudWatchメトリクスを適用すると、読み取りリクエスト量と待ち時間などロードバランサーとターゲットのデータポイントに関する統計情報をメトリクスとして取得できる。これらのメトリクスを使用してシステムが正常に実行されていることを確認できる

・プロキシサーバーにより、クライアントからの要求をフィルターし製品の更新に関連する要求のみを許可して製品の更新以外の全ての要求をフィルタリングすることができる(ネットワークACLおよびセキュリティグループはURLに基づいてリクエストをフィルタリングすることができない)

・CloudWatch Eventのターゲットとして設定できるサービス  EC2、Lambda関数、Kinesis Data Stream、Kinesis Data Firehoseの配信ストリーム、ECSタスク、Systems Manager Run Command、Systems Manager オートメーション、Batchジョブ、Step Functionステートマシン、CodePipelineの倍プライン、Code Buildプロジェクト、Inspectorの評価テンプレート、SNSのトピック、SQSキュー、EC2 CreateSnapshot API call、EC2 Rebootlnstances API call、EC2 StopInstances API call、およびEC2 TerminateInstances API Call、別のAWSアカウントのデフォルトのイベントパス

・アプリケーションエラーに関連するキーワードをCloudWatchログを調べることで確認し、そのキーワードに基づいてカスタムメトリックを作成できる。さらに、そのキーワードに関するイベントをトリガーとしてEC2インスタンスを再起動するアクションを作成し、そのアクションを呼び出すカスタムメトリクスのCloudWatchアラームを設定できる

・CloudWatchアラームアクションを使用し、EC2インスタンスを自動的に停止、終了、再起動または回復するアラームを作成できる  このアラームを利用して、インスタンスを実行する必要がなくなった際に停止または終了アクションを使用できる

・CloudTrailログファイルの整合性の検証を使用することでCloudTrailによるログ配信後にそのログファイルが変更、削除、または変更されなかったどうかを判断することができる

・RedsiftはRDSと異なり、マルチAZ構成によるフェールオーバー機能がないため冗長性が低いデータベース  シングルAZ構成しか実行できないため、Redshiftはスナップショットを利用しローカルおよびリモートの量リージョンでデータをセキュアにバックアップすることが最良のソリューション

DHCP(Dynamic Host Configuration Protocol)  TCP/IPネットワークのホストに設定情報を渡すための規格  DHCPメッセージのoptionsフィールドの内容は設定パラメータ  パラーメータにはドメイン名、ドメインネームサーバー、netbios-node-typeなどがある  DHCPオプションセットでは、VPC上で利用できるDHCPオプションで必要なオプションのみ指定できる

・カスタムメトリクスを使用する場合はPutMetricData権限が必要  PutMetricDataがカスタムメトリクスを呼び出すとアプリケーションの1分未満のアクティビティをより短期間に把握できる

LDAPActive Directoryとのデータ読み書きに使用される標準的な通信プロトコル

・CloudFormationテンプレートにおけるCreationPolicy属性のResourceSignalパラメーターで、30分のTimeoutプロパティを追加することで、前提条件となるAWSリソースが起動されるまでのタイムアウト時間を設定することができる

Go echo

go mod の作成

go mod というファイルでパッケージ管理(外部ライブラリの管理)を行う

go mod init プロジェクト名
go mod init $(basename `pwd`)

※basename pwdでカレントディレクトリの取得

echo

軽量なWebフレームワーク

package main

import (
  "net/http"
  
  "github.com/labstack/echo"
  "github.com/labstack/echo/middleware"
)

var e = createMux()

func main() {
  e.GET("/", articleIndex)
  e.Logger.Fatal(e.Start(":8080"))
}

func createMux() *echo.Echo {
  // Echoのインスタンス作成
  e := echo.New()

  // 各種ミドルウェアを設定
  e.Use(middleware.Recover())
  e.Use(middleware.Logger())
  e.Use(middleware.Gzip())

  return e
}

func articleIndex(c echo.Context) error {
  return c.String(http.StatusOK, "Hello, World!")
}
var e = createMax()

Goプログラム(パッケージ)を実行した際は、依存パッケージの読み込み > グローバル定数 > グローバル変数 > init() > main() の順に実行(判定)されてく そのため、main()とinit()よりも先に上記のグローバル変数の部分が処理され、createMux()関数が呼び出される 上記のソースコードはmainパッケージのグローバル変数であるeにcreateMux()関数の戻り値を格納している箇所

パッケージの依存関係の管理

外部パッケージであるechoを利用するため、プログラムを起動する際にはechoのソースコードも必要 こうした外部パッケージを管理する手段として、Goではgo modコマンドが準備されている

go mod tidy

上記のコマンドは、ソースコードを検査して、どのような外部パッケージを利用しているのかを判定する ソースコード内で利用されている外部パッケージはgo.modとgo.sumというファイルに書き出される 直接的に利用しているパッケージはgo.modに間接的に利用しているパッケージはgo.sumに記載される go mod tidyコマンドで依存パッケージの書き出しが完了した後、外部パッケージのソースコードをPCにダウンロード(キャッシュ)する

go mod download

ダウンロードされた外部パッケージのソースコードは$HOME/go/pkg/modに配置される