エンジニアのひよこ_level10

毎日更新してた人。たまに記事書きます。

【Laravel】URLが『/hoge』のように、.phpが要らない理由【291日目】

普通のページなら

phpの普通のページだと、URLは

https://domain.jp/hoge/huga.php

のように、phpをつける必要がありました。

では、なぜLaravelはそれが必要ないのでしょう。

必ずindex.phpを開いてるから

これはURLがなにであろうと、ドキュメントルートのindex.phpを開いているからです。

https://domain.jp/hoge/huga

と書いていても、開くのは、ドキュメントルートのindex.phpです。

そして、そのindex.phpが、route.phpを読み込んで、目的のページを表示させています。

では、どうやって必ずindex.phpを読み込ませているのか

.htaccessに秘密が

    RewriteEngine On

    ## Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)/$ /$1 [L,R=301]

    ## Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]

URLの最後がスラッシュなら、残りを第一引数に渡したり、
強制的にindex.phpを呼び出したり。

あーここでいろいろしてたんですね。

nginxの場合

ちなみに、nginx+php-fpmとかで構築してるときには、nginxの方でも設定されてることもあります。

詳しくはこちらへ

willow710kut.hatenablog.com

【PHP】cloneを使う時って?オブジェクトはそのままコピーできない?【267日目】

オブジェクトのコピーはできない?

$item = new Item();
$item->value = 1;

// コピー?
$item2 = $item;

$item2->value = 2;

この時、$itemと$item2の値はどうなるでしょう?

実は両方一緒

// 2
$item->value;
// 2
$item2->value;

あれ?なんで?

インスタンスの変数のコピーは、実際は参照を渡しているだけ

// コピー?
$item2 = $item;

ここが問題。

この$itemの中には、インスタンスの『参照』を持っている。

つまり、 new Item();の保存先。実際の値は違いますが、
0x4842ffaaみたいに、住所が保存されています。

だから、住所をコピーしたところで、住所の先の家が変わるわけではないので、
$itemと$item2の中身は実質一緒ってことになります。

だから、 $item2->value = 2;で、$itemも$item2も両方書き換わったわけですね。

じゃあどうするの?

$item2 = clone $item;

これでOK。 clone $itemで、同じ内容で、新しいオブジェクトを作ってくれる。
その参照先を$item2に保存するので、$itemと$item2は異なる値になる。

こういう時に、cloneを使うんですね。

参照先

PHP: オブジェクトのクローン作成 - Manual

【PHP】traitを使って、関数を余分な場所に読み込ませない【223日目】

注意

traitの本質とは違います。オブジェクト指向とかも触れません。

ただ、trait使った時に、実際の動きとしてどんな違いが出るかについてのメモ書きになります。

2つのファイル

hello.php

<?php
public function sayHello() {
    echo 'Hello World!';
}

human.php

<?php
require_once 'hello.php'

class boy {
    public function main() {
        sayHello();
    }
}

class girl {
    public function main() {
        sayHello();
    }
}

sayHello();

これだと、human.phpの中は全てhello.phpのsayHello()が読み込めてしまう。

違うんだ。私はboyクラスにだけsayHello()をもたせたかったんだ。

traitを使ってみる

hello.php

trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

human.php

<?php
require_once 'hello.php'

class boy {
    use HelloWorld;
    public function main() {
        $this->sayHello();
    }
}

// sayHello(); 読み込めない

これでよし。

公式ドキュメント

PHP: トレイト - Manual

【PHP】'1.0' == '1'がtrueだった。【210日目】

なんで起こるの?

比較に数値形式の文字が含まれる場合は、文字列が 数値に変換され

PHP: 比較演算子 - Manual

値をテストしてみた

>>> "a" == "0"
=> false
>>> "a" == 0
=> true
>>> "1.0" == "1"
=> true
>>> "1.0" == 1
=> true
>>> "1.0" === "1"
=> false

== を使う時は気をつけよう

“1.0” == “1"
=> true
“1.0” === “1"
=> false

比較演算子の動きを理解しないと、意図しない動作をしてしまうので、
文字列同士で比較したとしても、===を忘れない方がいいなと思いましたという共有でした。

【PHP】HTMLのclassを指定して要素を取得。DomCrawler【209日目】

こんな時に使う

<div class="aaa">
    <p class="aaa">aaaaa</p>
    <img src="/test/img.png">
</div>

これの、src部分 /test/img.pngが欲しい。

DomCrawler使ってみよう

これ使うと、CSSセレクタ使って取得が出来る。

簡単。見やすい。

■DomCrawler
https://symfony.com/doc/current/components/dom_crawler.html

テスト用コード

(Laravelでphp artisan tinkerとかしていただければ試せます)

use Symfony\Component\DomCrawler\Crawler;

$html = <<< EOF
<div class="aaa">
<p class="aaa">aaaaa</p>
<img src="/test/img.png">
</div>
EOF;

$crawler = new Crawler($html);
$srcs = $crawler->filter('.aaa img')->each(function (Crawler $c) {
return $c->attr('src');
});

結果

=> [
"/test/img.png",
]

【PHP】表示させたページに404のステータスコードをつける【206日目】

こんな時に使う

PHPでオリジナルの404ページを表示させたい。

で、ページが例外に入った時にオリジナルの画面を表示させたけど、
ステータスコードが200で正常に表示されている時。

このコード付け足す

header("HTTP/1.1 404 Not Found");

これでステータスコードが404になっています。

google chromeのNetworkの項目とかで確認してみましょう。

【PHP】PDO使ってSQL文タイポした時にExceptionを投げる【195日目】

こんな時に使う

(PDO使う時ほぼないというツッコミは置いておいて)

 $dbh->exec('CREATE TBLE Pages (id int, name nchar(255), create_date datetime)');

あ、 TABLETBLEになってる。
でもエラー出てないから気づかなかった・・・

って時に、エラーを投げてやりたい。

こうかく

PDOのオブジェクトを生成する時に、
第四引数に、 array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)を渡してやる。

$dbh = new PDO('mysql:host=mysql;dbname=dbname',
                'username',
                'password',
                array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

これで、構文間違えた時もエラーが出る。
try catchとかで、rollbackさせたい時とかどうぞ。

公式ドキュメント

PHP: PDO::__construct - Manual

ここで使うOption

PHP: 定義済み定数 - Manual

【PHP】相対パスでincludeした後のファイルで、さらにincludeすると読み込めない【194日目】

こんなファイル作りました

public/index.php

include ../xxx/yyy/temp.php

xxx/yyy/temp.php

include ../../zzz/item.php

zzz/item.php

echo 'hello';

これ、動かないです。

どこが問題か

xxx/yyy/temp.php

include ../../zzz/item.php

これ。単体で見たら問題なさそう。
でも、このファイルをincludeすると話は別。

includeは、ファイルの中身を、自分にコピーするイメージ

includeはファイルの中身をコピーするイメージ。

だから、最初のincludeでこんな風になる。

public/index.php

// include ../xxx/yyy/temp.phpで呼び出した
include ../../zzz/item.php

そう、public/index.phpから相対パス../../zzz/item.phpを呼び出してしまうのだ。

だから、publicより下のディレクトリを読み出そうとするし、目的のディレクトリなんて存在しない。

反省

ということで、ファイルをincludeするなら、基本的に絶対パス使おう。