forget for get

覚えるために忘れる

Builderパターン

Builderパターン

複雑なインスタンスを構築する。
Builderクラスが構築のためのメソッドを定義。
Directorクラスがそのメソッドを使ってインスタンスを構築する。
具体的な処理はBuilderクラスのサブクラスが決める。

DirectorはBuilderのメソッドのみを使う。
実際に渡されるサブクラス(TextBuilder、HTMLBuilder)がどれかは知らない。
知らないからこそ、入れ替えができる。

 

Builder.php

abstract class Builder {
  abstract function makeTitle(string $title): void;
  abstract function makeString(string $str): void;
  abstract function makeItems(array $items): void;
  abstract function close(): void;
}

Director.php

class Director {
  private $builder;
  function __construct(Builder $builder) {
    $this->builder = $builder;
  }
  function construct(): void {
    $this->builder->makeTitle("あいさつ");
    $this->builder->makeString("午前");
    $this->builder->makeItems(["おはよう","こんにちは"]);
    $this->builder->makeString("午後");
    $this->builder->makeItems(["こんばんは","おやすみ","さよなら"]);
    $this->builder->close();
  }
}

TextBuilder.php

class TextBuilder extends Builder {
  private $buffer = "";
  function makeTitle(string $title): void {
    $this->buffer .= "==========\n"
      . "『".$title."』\n\n";
  }
  function makeString(string $str): void {
    $this->buffer .= "■".$str."\n\n";
  }
  function makeItems(array $items): void {
    foreach ($items as $item) {
      $this->buffer .= " ・".$item."\n";
    }
    $this->buffer .= "\n";
  }
  function close(): void {
    $this->buffer .= "==========\n";
  }
  function getResult(): string {
    return $this->buffer;
  }
}

HTMLBuilder.php

class HTMLBuilder extends Builder {
  private $filename;
  private $buffer = "";
  function makeTitle(string $title): void {
    $this->filename = $title.".html";
    $this->buffer .= "<html><head><title>".$title."</title></head><body>"
      . "<h1>".$title."</h1>";
  }
  function makeString(string $str): void {
    $this->buffer .= "<p>".$str."</p>";
  }
  function makeItems(array $items): void {
    $this->buffer .= "<ul>";
    foreach ($items as $item) {
      $this->buffer .= "<li>".$item."</li>";
    }
    $this->buffer .= "</ul>";
  }
  function close(): void {
    $this->buffer .= "</body></html>";
    file_put_contents($this->filename, $this->buffer);
  }
  function getResult(): string {
    return $this->filename;
  }
}

Main.php

require "../autoload.php";
if (!isset($argv[1])) {
  echo "引数を指定してください\nphp Main.php [plain/html]";
  return;
}
if ($argv[1] == "plain") {
  $textBuilder = new TextBuilder();
  $director = new Director($textBuilder);
  $director->construct();
  echo $textBuilder->getResult();
} else if ($argv[1] == "html") {
  $htmlBuilder = new HTMLBuilder();
  $director = new Director($htmlBuilder);
  $director->construct();
  $filename = $htmlBuilder->getResult();
  echo $filename . "が作成されました";
}

autoload.php

function autoload($className){
  require './'.$className.'.php';
}
spl_autoload_register('autoload');

Factory Methodパターン

Factory Methodパターン

インスタンスの作り方をスーパークラス側で定める。
具体的な肉付けはサブクラス側で行う。

 

Product.php

abstract class Product {
  abstract public function use(): void;
}

Factory.php

abstract class Factory {
  final public function create(string $owner): Product {
    $p = $this->createProduct($owner);
    $this->registerProduct($p);
    return $p;
  }
  abstract protected function createProduct(string $owner): Product;
  abstract protected function registerProduct(Product $product): void;
}

IDCard.php

class IDCard extends Product {
  private $owner;
  function __construct(string $owner) {
    echo $owner."のカードをつくります。\n";
    $this->owner = $owner;
  }
  public function use(): void {
    echo $this->owner."のカードを使います。\n";
  }
  public function getOwner(): string {
    return $this->owner;
  }
}

IDCardFactory.php

class IDCardFactory extends Factory {
  private $owners = [];
  protected function createProduct(string $owner): Product {
    return new IDCard($owner);
  }
  protected function registerProduct(Product $product): void {
    $owners[] = $product->getOwner();
  }
  public function getOwners(): array {
    return $owners;
  }
}

Main.php

require "../autoload.php";
$factory = new IDCardFactory();
$card1 = $factory->create("佐藤");
$card2 = $factory->create("鈴木");
$card1->use();
$card2->use();

実行結果

佐藤のカードをつくります。
鈴木のカードをつくります。
佐藤のカードを使います。
鈴木のカードを使います。

autoload.php

function autoload($className){
  require './'.$className.'.php';
}
spl_autoload_register('autoload');

PHP エルビス演算子(?:)とNull合体演算子(??)

呼び方を忘れるので。

エルビス演算子三項演算子(?:)

$a = $b ?: 0;
$bがTRUEだったら$b、違ったら0。
「$b ? $b : 0」と同等。

Null合体演算子(??)

$a = $b[0] ?? 0;
$b[0]がNULLじゃなかったら$b[0]、NULLだったら0。

「isset($b[0]) ? $b[0] : 0」と同等。

https://www.php.net/manual/ja/language.operators.comparison.php

FlatBuffersチュートリアル(日本語)PHP

公式ドキュメントが英語で、日本語の情報があまりみつからないので、やってみてまとめます。
公式チュートリアルは1ファイルで書き読みやってるけど、今回は書き・読み2ファイルに分けます。

 

FlatBuffersとは

Google社が開発しているクロスプラットフォーム対応のシリアライゼーションライブラリ。
Jsonと違い、パースやunpackingが不要でデータにアクセスできるので高速。
Cocos2d-x、FacebookAndroidアプリなどで使われている。

https://google.github.io/flatbuffers/index.html

 

環境

centos8、PHP7.4

 

作業ディレクトリ作成

mkdir fbwork
cd fbwork

 

FlatBuffersをクローン

git clone https://github.com/google/flatbuffers.git

flatbuffers/php/下にphp用のライブラリがある

flatc(FlatBuffersのコンパイラ)をビルド(初回のみ)

yum install gcc-c++ cmake
cd flatbuffers
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
make
ln -s /flatbuffersのフルパス/flatc /usr/local/bin/flatc
cd ../

スキーマを作成

vi monster.fbs

namespace MyGame.Sample;
enum Color:byte { Red = 0, Green, Blue = 2 }
struct Vec3 {
  x:float;
  y:float;
  z:float;
}
table Monster {
  pos:Vec3;
  hp:short = 100;
  name:string;
  color:Color = Blue;
  weapons:[Weapon];
}
table Weapon {
  name:string;
  damage:short;
}
root_type Monster;

 スキーマコンパイル

flatc --php monster.fbs

MyGame/Sample/以下にファイルが作成される
Color.php Monster.php Vec3.php Weapon.php

 

書き込みサンプル

vi WriteSample.php

<?php
function __autoload($class_name) {
  $class = substr($class_name, strrpos($class_name, "\\") + 1);
  $root_dir = dirname(__FILE__);
  $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "flatbuffers", "php")),
                 join(DIRECTORY_SEPARATOR, array($root_dir, "MyGame", "Sample")));
  foreach ($paths as $path) {
    $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php"));
    if (file_exists($file)) {
      require($file);
      break;
    }
  }
}

$builder = new \Google\FlatBuffers\FlatbufferBuilder(1024);

$weapon_one_name = $builder->createString("Sword");
$sword = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_one_name, 3);
$weapon_two_name = $builder->createString("Axe");
$axe = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_two_name, 5);

$weaps = array($sword, $axe);
$weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps);

$name = $builder->createString("Orc");

$pos = \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);

\MyGame\Sample\Monster::StartMonster($builder);
\MyGame\Sample\Monster::AddPos($builder, $pos);
\MyGame\Sample\Monster::AddHp($builder, 300);
\MyGame\Sample\Monster::AddName($builder, $name);
\MyGame\Sample\Monster::AddColor($builder, \MyGame\Sample\Color::Red);
\MyGame\Sample\Monster::AddWeapons($builder, $weapons);
$orc = \MyGame\Sample\Monster::EndMonster($builder);

$builder->finish($orc);
file_put_contents("monster.dat", $builder->sizedByteArray());

 

php WriteSample.phpと実行すると、バイナリファイル(monster.dat)が生成される。

読み込みサンプル

vi ReadSample.php

<?php
function __autoload($class_name) {
  $class = substr($class_name, strrpos($class_name, "\\") + 1);
  $root_dir = dirname(__FILE__);
  $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "flatbuffers", "php")),
                 join(DIRECTORY_SEPARATOR, array($root_dir, "MyGame", "Sample")));
  foreach ($paths as $path) {
    $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php"));
    if (file_exists($file)) {
      require($file);
      break;
    }
  }
}

$contents = file_get_contents("monster.dat");
$bb = \Google\FlatBuffers\ByteBuffer::wrap($contents);

$monster = \MyGame\Sample\Monster::GetRootAsMonster($bb);

echo $monster->getHp() . "\n";
echo $monster->getName() . "\n";
echo $monster->getColor() . "\n";
echo $monster->getPos()->getX() . "\n";
echo $monster->getPos()->getY() . "\n";
echo $monster->getPos()->getZ() . "\n";

 

php ReadSample.phpと実行すると、バイナリファイル(monster.dat)を読み込んだ結果を表示します。

 

FlatBufferバイナリをJSONにパース

flatc --json --raw-binary monster.fbs -- monster.dat

JSONファイル(monster.json)が生成される

 

参考

公式チュートリアル

https://google.github.io/flatbuffers/flatbuffers_guide_tutorial.html

FlatBuffersをPHPで使ってみる

https://labs.gree.jp/blog/2015/11/14495/

 

WindowsアップデートしたらVM(VirtualBox、Vagrant)が起動しなくなった

結論から書くと、

WindowsアップデートしたらVMが起動しなくなった。

Windowsアップデートでホストオンリーアダプタが消えてしまったのが原因。

Virtualboxを起動して、「ファイル」→「ホストネットワークマネージャー」で

既存の設定を「x除去」、新規で「+作成」(必要ならIPアドレスを設定)

VMの「設定」→「ネットワーク」→「アダプター2」で、作成したホストオンリーアダプタを選択

VMを起動して解決!

 

 

職場についたらまずPC起動して、vagrant upでVMを起動します。

しかし、VMの起動に失敗しました。

こんなエラーコード、、

「Stderr: VBoxManage.exe: error: Failed to open/create the internal network 'HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter' (VERR_INTNET_FLT_IF_NOT_FOUND)」

「VBoxManage.exe: error: Failed to attach the network LUN (VERR_INTNET_FLT_IF_NOT_FOUND)」

「E_FAIL (0x80004005)」

 

ためしにVirtualBox起動して、そっちから起動してみるも、

同じエラーコードを表示して失敗、、

「E_FAIL (0x80004005)」

 

Windowsアップデートした直後だったので、それが原因くさい。

 

ググってみると、VirtualBoxをアップデートしろだの、Vagrantをアップデートしろだのある。

 

結果的にはこれと同じでした。

tyoimemo.blogspot.jp

 

Windowsアップデートでホストオンリーアダプタが消えてしまったらしい。

Virtualboxを起動して、「ファイル」→「ホストネットワークマネージャー」で

既存の設定を「x除去」、新規で「+作成」(必要ならIPアドレスを設定)

VMの「設定」→「ネットワーク」→「アダプター2」で、作成したホストオンリーアダプタを選択

VMを起動して解決!

 

VirtualBoxVagrantの最新バージョンをインストールしなおしてVM作り直して、結局同じエラーで起動に失敗して、最終的に以前遭遇して解決した問題と同じだったっていう、、

 

 

 

Oculus Quest2+Virtual Desktop+WiFi6でPCVRを無線で体験

事前準備

こちらを参考に。

 【OculusQuest】無線でPC版のVRが体験できる!Virtual Desktopの使い方 | CGメソッド

PCにSteam、SteamVR、Virtual Desktopをインストール。

エストにVirtual Desktop(有料)をインストール。

SideQuestからクエストにVirtual Desktopのパッチをインストール。

使ってみる

バーチャルデスクトップストリーマーを起動
エストでバーチャルデスクトップを起動
steam起動して右上のVRを押す

Oculus Quest2でclusterに入る

上の状態で、ブラウザからcluster起動

WiFi6ルーター

WiFi6じゃないと映像や音声が途切れ途切れになる可能性があります。