ざっくりん雑記

プログラミングで忘れそうなことをひたすらメモる

PHP - 関数のパラメータ

関数を定義するとき、任意の値を引数(パラメータ)として渡すことができる。

渡す方法として、値渡し参照渡しがある。

値渡しのパラメータ

大抵の場合は、こちらを使う。引数には任意の式を指定でき、式の内容が評価された後の値が関数に渡される。

<?php

function greeting($name) {
    echo $name."さん。おはよう。";
}

$name = "azunobu";
greeting($name);

例として、こういったかたちで書ける。

参照渡しのパラメータ

参照渡しでは、通常のスコープの規則を無視し、関数内から直接変数の値を操作する。そのため、参照渡しではパラメータとして変数を渡す必要がある。 参照で渡す、ということを明示するには関数のパラメータリストの引数名の前にアンパサンド記号(&)を付ける。

<?php

function greeting(&$personName) {
    echo $personName."さん。おはよう。";
}

$name = "azunobu";
greeting($name);

この例では、関数内の$personNameは参照渡しで渡されているので、直接$nameを参照している。 そのため、値の変更も関数内で直接変更を加えることができる。

また、参照渡しの主な恩恵としては、変数をコピーする必要がない。PHPでは、値渡しを行うと関数を実行する前に値の内容のコピーを作成する必要がある。 長い文字列や大きなオブジェクトの場合、このコピーは大きなコストになり実行速度にも影響を与えかねない。 参照渡しはこの点、コピーをせず直接参照できるため有利。

可変パラメータ

関数のパラメータの数を可変にしたい、という時もある。 PHP5.6以降であれば、パラメータリストに ... トークンを含めることで、 その関数が可変長の引数を受け取ることを示すことができる。

<?php

function sum(...$numbers) {
    $total = 0;
    foreach ($numbers as $num) {
        $total += $num;
    }
    return $total;
}

echo sum(1, 2, 3, 4, 5, 6, 7, 8, 9);

出力結果は45となる。

タイプヒンティング

渡ってきたパラメータが特定のクラス(あるいは特定のクラスを継承したクラス)のインスタンスであるか?コールバック関数であるか?…というバリデーション的なことが可能。

この部分の説明に関しては、とても分かりやすく解説された記事があるため、こちらを紹介します。

dekokun.github.io

参考

プログラミングPHP 第3版

プログラミングPHP 第3版

PHP: ユーザー定義関数 - Manual

PHP: 関数の引数 - Manual

PHPでコールバック関数を利用する - Qiita

PHP - キャスト演算子

値を特定の型として扱いたい

PHPは元々、弱い型付けの言語であるが、特定の型として扱いたい場面もある。 そういった時は以下のキャスト演算子でキャストすることも可能。

PHPのキャスト演算子

演算子 同じ意味の演算子 変更後の型
(int) (integer) 整数
(bool) (boolean) 論理値
(float) (double), (real) 浮動小数点数
(string) 文字列
(array) 配列
(object) オブジェクト
(unset) NULL

(string) に関してはstrval()関数と同様。

参考

プログラミングPHP 第3版

プログラミングPHP 第3版

PHP (PDO) - Unknown character set

PDOクラスにおいてのDB接続時エラー

define('DSN', 'mysql:host=localhost;dbname=hoge;charset=utf-8;');
define('USER', 'piyouser');
define('PASSWORD', '1234');

try {
    $dbh = new PDO(DSN, USER, PASSWORD);
    echo '接続に成功しました。'.'<br>';
} catch (PDOException $e) {
    echo $e->getMessage();
    exit;
}

エラー:SQLSTATE[HY000] [2019] Unknown character set

MySQLに対してのcharsetはutf-8ではなくutf8です。 HTMLを書いているとcharset=utf-8なので、その辺と混同して間違いやすいですね。 気をつけよう。

参考

PHP - データ型

 ざっくり、PHPには8種類のデータ型がある。

  • スカラー型(単一の値を取る)
  • 複合型(コレクション)
    • 配列
    • オブジェクト
  • 特殊型
    • リソース
    • NULL

整数

  • 10進形式、8進形式、16進形式そして2進形式の4通り

10進形式

2016
-321
+321

8進形式

8進数と見なされるには

  • 先頭が0
  • その後、0から7までの数字で続ける

とする。プラス・マイナスといった符号が付けられる。

0755         # 10進形式だと493
+010         # 10進形式だと8

16進形式

16進数と見なされるには

  • 先頭が0x
  • その後に数字(0,1)あるいは英字(AからF)で続ける

とする。英字は小文字/大文字は問わない。通常は大文字。符号付けられる。

0xFF         # 10進形式だと255
0x10         # 10進形式だと16
-0xDAD1      # 10進形式だと-56017

2進形式

2進数と見なされるには

  • 先頭が0b
  • その後に数字(0,1)で続ける

とする。符号付けられる。

0b00000001         # 10進形式だと1
0b00000010         # 10進形式だと2
-0b10              # 10進形式だと-2

その他

  • 整数値の範囲を超えた場合、数値以外を代入しようとした場合、自動的に浮動小数点への変換が行われる
  • 整数値かどうか調べる
if (is_int($number)) {
    // $numberは整数
}

浮動小数点数

PHPでの浮動小数点数の表し方

  • 普段見慣れている形式
3.14
0.00211
-432.122
  • 科学で用いられる記法
0.314E1     # 0.314*10^1 -> 3.14
17.0E-3     # 17.0*10^(-3) -> 0.017

浮動小数点数はあくまでも近似値

まず、注意したいのは、浮動小数点数どうしを比較する(==)コードは書いてはいけないこと。

たとえば「5.5」という値、多くのシステム上では「5.499999999999」という値で表されている。浮動小数点数が正確な値であると、期待してはいけない。

じゃあ、どう比較すればいいの? -> 小数点以下の特定桁数までのみで比較しよう

例として小数点以下3桁までを対象として比較するコードを示す。

if (intval($number_a * 1000) == intval($number_b * 1000)) {
    // 小数点以下3桁までは共通
}

その他

if (is_float($number)) {
    // $numberは浮動小数点数
}

文字列

 PHPは、Webで用いられる言語として多くの文字列操作機能を標準で組み込んでいる。  文字列とは、任意の長さの文字列を連結したもので、文字列リテラルを表すには、シングルクォート(')ダブルクォート(")で囲む。

  • ダブルクォート
    • その内部の変数は展開される
  • シングルクォート
    • 内部に変数があっても展開されない
$sushi = "maguro";
echo "Ah, I want to eat $sushi\n"
echo 'Ah, I want to eat $sushi'

上記を実行すると

Ah, I want to eat maguro
Ah, I want to eat $sushi

という結果になり、シングルクォートの変数は展開されないことがわかる。

2つの文字列が等しいかどうか

比較演算子 == を用いる。

if ($a == $b) {
  echo "aとbは等しい"
}

ある値が文字列であるかどうか

is_string()関数を用いる。

if (is_string($string)) {
  echo "$string は 文字列です"
}

その他

文字列はその他、多くの関数があるが、ここではひとまず触れないこととする。

論理値

 論理値とは、何かが真か偽かを表す。以下のように条件指定で調べる。

if ($alive) { ... }

PHPでfalse(偽)であるとみなされるもの

  • 整数値0
  • 浮動小数点数0.0
  • 空の文字列("")および文字列"0"
  • 素数がゼロの配列
  • プロパティやメソッドを一切持たないオブジェクト
  • NULL

逆に言えば、以上のもの以外はすべてtrueである。

ある値が論理値かどうか調べる

  • is_bool()関数を用いる。
if (is_bool($a)) {
    // $aは論理値
}

配列

 配列は、いくつかの値を一括して管理する。個々の値はゼロから始まる番号、あるいは文字列を指定して取得する。

$sushi[0] = "maguro";
$sushi[1] = "salmon";
$sushi[2] = "egg";

$favorability['maguro'] = "めっちゃ好き";
$favorability['salmon'] = "わりと好き";
$favorability['egg'] = "嫌いじゃない";

 array()構文にて作成する。

$sushi = array("maguro", "salmon", "egg");
$favorability = arrya('maguro'     => "めっちゃ好き",
               'salmon'     => "わりと好き",
               'egg'        => "嫌いじゃない");

 個々の値を処理する方法はいろいろある。最もよく使われているのはforeachループ。

foreach ($sushi as $neta) {
  echo "I like {$neta}\n";
}

foreach ($favorability as $neta => $rate) {
  echo "{$neta} はどれくらい好き勝手言うと… {$rate}かな?\n";
}

 上のコードが実行されると、以下の様な出力がされる。

I like maguro
I like salmon
I like egg
maguro はどれくらい好きかという… めっちゃ好きかな?
salmon はどれくらい好きかという… わりと好きかな?
egg はどれくらい好きかという… 嫌いじゃないかな?

 という感じ。

ある値が配列かどうか調べる

  • is_array()関数を用いる。
if (is_array($x)) {
    // $xは配列
}

その他

このような関数以外にも要素をソートする関数、要素数を数える関数など配列を操作する関数は数多くある。

オブジェクト

 PHPでは、オブジェクト指向プログラミングをサポートしている。クラスとは、オブジェクト指向設計で用いられる一つの部品であり、プロパティ(変数)やメソッド(関数)を持つ構造体のようなものである。クラスの定義はclassで行う。

class Sushi
{
    public $name = '';

    function name ($newname = NULL)
    {
        if (!is_null($newname)) {
            $this->name = $newname;
        }

        return $this->name;
    } 
}

 一度クラスを定義すれば、newキーワードを用いていくつでもそのオブジェクトを生成することができる。オブジェクトのプロパティやメソッドにアクセスする際には、->を用いる。

$maguro = new Sushi;
$maguro->name('まぐろ');
echo "めっちゃ新鮮な、 {maguro->name}\n";
$salmon = new Sushi;
$salmon->name('サーモン');
echo "めっちゃ新鮮な、 {salmon->name}\n";
めっちゃ新鮮な、 まぐろ
めっちゃ新鮮な、 サーモン

ある値がオブジェクトかどうか調べる

  • is_object()関数を用いる。
if (is_object($x)) {
    // $xはオブジェクト
}

リソース

 多くのモジュールには、PHPの外部の世界とやり取りするための関数が用意されている。  データベース関連の拡張モジュールであれば、

  • データベースへの接続
  • クエリの送信
  • データベースとの接続解除

 といったようなメソッドがある。  一度に複数のデータベース接続を扱うこともあるため、接続用関数は、確立した一意な接続を表す識別子を返すようになっている。この識別子を、リソース(またはハンドル)という。  アクティブなリソースは、各々が一意な識別子をもつ。その識別子は数値のインデックスとなっている。

 PHPの内部ルックアップテーブルはこのリソースを保持し、参照することになっている。コード内でそのリソースが参照されている(使用されている)数などを、このテーブルで管理する。作成したリソースへの参照がなくなった時点で、そのリソースを作成した拡張モジュール自身がメモリの解放などの後始末を行う。

 関数内でリソースをローカル変数に代入してしまえば、関数が終了した時点でそのローカル変数への参照はなくなる、つまりその変数の値がPHPの管理下に戻るため、後始末が自動的に実行させることができる。

 多くの拡張モジュールでは、後始末用の関数を個別で用意しているため、自動的なリソース解放に頼らずとも、明示的にその関数を呼び出すことでリソースを開放することも可能であったりする。

ある値がリソースかどうか調べる

  • is_resource()関数を用いる。
if (is_resource($x)) {
    // $xはリソース
}

NULL

 NULLが表す値は1つだけ、NULLである。これは、大文字/小文字を区別しない。  NULLということは、その変数に何も値が代入されていないことを表す。(PerlPythonでいうNoneと同じ意味)

$sushi = "maguro";
$sushi = "null";    // 変数の値が解除
$sushi = "Null";    // 上と同じ
$sushi = "NULL";    // 上と同じ

ある値がNULLかどうか調べる

  • is_null()関数を用いる。
if (is_null($x)) {
    // $xはNULL
}

参考

プログラミングPHP 第3版

プログラミングPHP 第3版

PHP - 字句構造(基本的ルール)

PHPにおける字句構造について

 プログラミング言語についての「字句構造」とは、その言語を記述しプログラミングをしていく上での基本的なルールのこと。最も下位レベルでの文法規則と言える。

大文字/小文字の区別

組み込みキーワードは区別しない

 定義するクラスや関数の名前、echo、while、classといった組み込まれているキーワードの名前は、大文字と小文字が区別されない。よって以下の3行のコードは同一の意味を持つ。

echo("hello, php");
ECHO("hello, php");
Echo("hello, php");

変数名は区別する

 一方で、変数名については大文字と小文字を区別する。

$count;
$Count;
$COUNT;

 以上は全て異なる変数を表す。

命令文

   PHPは、命令文の区切りとしてセミコロンを用いる(;)。 if文やwhile文における波括弧({})に包括されたコード群の、閉じ括弧については、セミコロンは不要。 終了タグ直前のコードはセミコロンが不要で省略できる。省略可能であってもややこしかったり、なんだかヒヤヒヤするし、後の可読性も落ちるので必ず付けておくと良さそう。

<?php
if ($name == $admin) {
    echo "Administratorですね"; // このセミコロンは必須
}                               // 閉じ括弧にセミコロンは不要
echo "Hello, PHP!"               // 終了タグ直前のセミコロンは省略可
?>

空白と改行

 PHPにおける空白文字はプログラムに影響を与えない。ので、自由に行頭を揃えたり、インデントするなどして可読性の高いコードを書くことができる。

fruit($apple, $banana, $kiwi, $grape);

// こんな風にも書ける

fruit(
    $apple,
    $banana,
    $kiwi,
    $grape
);

コメント

 適度にコメントを書こう。これはPHPに限った話ではない。

// ✕:よくないコメント

$x = 17; // 変数$xに17を代入する

// ○:よさげなコメント

// &#nnn; 形式のエンティティを文字に変換する
$text = preg_replace('/&#([0-9])+;/e', "chr('\\1')", $text);

シェル形式コメント

 ハッシュ記号(#)があると、そこから文末までがコメントとなる。目立つのでシェル形式コメントは、コードブロックの区切りとして使うのも良い。

if ($name == $admin) {
    # Adminなら
    echo "Administratorですね";
}   

##################
## ○○な関数
##################

$value = $height * $width; # 面積を計算

<?php $level = 4; # レベル4に設定 ?>レベル:<?php echo $level; ?>
レベル:4

 上記の最後の例は、PHPの終了タグでコメント範囲が終わるという点で、便利に使えるといえる。

C++形式コメント

if ($name == $admin) {
    // Adminなら
    echo "Administratorですね";
}   

///////////////////
// ○○な関数
///////////////////

$value = $height * $width; // 面積を計算

<?php $level = 4; // レベル4に設定 ?>レベル:<?php echo $level; ?>
レベル:4

C形式コメント

 シェル形式やC++はコメントが短い場合に便利。より長いコメントの場合はブロック形式のコメントが便利だが、PHPはブロック形式コメントもサポートしている。また、形式はC言語と同じ。

/*   こんな感じでC言語と同じように
    C言語と同様なブロック形式のコメントが
    PHPでも可能です。
    コードの一部を無効にしたい場合にも便利です。
    PHPの終了タグを包括すれば、その中身は無効になります。
    コメントを入れ子にすると、エラーが出るので気をつけよう。
*/

リテラル

 リテラルとは、以下の様なもの。

2016
0xFE
1.23456
"Hello, PHP"
'こんにちは'
true
null

識別子($)

変数名

OKな例
$name
$Count
$MAX_LENGTH
$_underscore
$_int
NGな例
$not number
$=
$50per

関数名

 関数名については、大文字/小文字が区別されない。 以下の関数名が有効。

checkPermission
list_all_admins
deleteName
UPPERCASE_IS_FOR_WIMPS
_hide

クラス名

 クラス名については、大文字/小文字が区別されない。 以下のクラス名が有効。

Person
User
Account

定数

 定数については、ある単純な値を保持する識別子のことで、指定できる値はスカラー値(論理値、整数、浮動小数点数、あるいは文字列)のみである。  定数の値を取得したい場合は、識別子を使用する。定数の値を設定したい場合はdefine()関数を使用する。

define(`MAX_LENGTH`, 100);
echo MAX_LENGTH

予約語(キーワード)

 言語自体に既に予約されており識別子として用いることができないキーワードは以下のリンクを参照。

参考

Ruby - シングルクウォートとダブルクォートの違い

結論から言うと、変数展開するかしないか

name = "寿司くん"

puts "こんにちは、#{name}"
# 結果:こんにちは、寿司くん

puts 'こんにちは、#{name}'
# 結果:こんにちは、#{name}

ダブルクォート「"」で囲んだ場合は、上記の通り、「#{変数}」とすると、変数を展開して変数に入っている値に置き換えられる。これを変数展開という。

シングルクォート「'」で囲んだ場合は、変数展開がされずに「#{変数}」はその文字列のままputsされる。

寿司くんって何


【自主制作アニメ】 寿司くん 第一話「出会い」(sushi-kun) - YouTube

「僕が世界で一番好きなもの、それはお寿司。高い地位や名誉よりも大切なものはお寿司。それぐらい僕はお寿司が好きだ。あぁ、お寿司が食べたいなぁ。」

たかし君 - アニメ寿司くん

寿司くん、好きです。

Ruby - %記法を使って手打ちで配列に要素を代入するやつ

%記法を利用する

a = ["a", "b", "c"]

こうやって配列に要素を入れるのが普通だけど何度もダブルコーテーションを打たねばならないので途中でアァァ!!!!!ってなる(ならないけど面倒くさい)

a = %W(a b c)

こうすれば、同じように配列に要素が入る(スゴイ)

一応動作確認

a = ["a", "b", "c"]
b = %W(a b c)
p a
p b
["a", "b", "c"]
["a", "b", "c"]

同じように配列ができている。

数値を%記法で入れたらどうなるか

a = ["a", "b", "c", 1 , 2, 3]
b = %W(a b c 1 2 3)
p a
p b
["a", "b", "c", 1, 2, 3]
["a", "b", "c", "1", "2", "3"]

文字列になって入ってる。 この文字列の ["1", "2", "3"] を数値として配列から取り出したい時は、

b = %W(a b c 1 2 3)
p b[3,3].map(&:to_i)
[1, 2, 3]

数値にして取り出せなくもないけど、なら最初から%記法を使わないで配列作ったほうがいいかもしれない。

参考

#12 %記法を使ってみよう | Ruby入門 - プログラミングならドットインストール

map, map! (Array) - Rubyリファレンス