ラベル MySQL の投稿を表示しています。 すべての投稿を表示
ラベル MySQL の投稿を表示しています。 すべての投稿を表示

2016年12月27日火曜日

MySQLとPHP/基本のメモ3

前回まではとりあえず書いてみたっていうだけでした。
今回は、ここのメソッドや変数について確認します。


メモ

カウンタ変数に色をついた名前を
文法関係や言語に関係なく、なかなか治らない自分の悪癖
同時にカウンタ変数にアクセスされる場合や、
後で放置されたカウント変数にアクセスしちゃう場合があり得るんですね。
エラーになってくれた方が、論理エラーがなくなって助かりますが。。。

ローカル変数をグローバルに
用途がよくわからないのですが、、、できるようです。
global $変数名;
宣言時にglobal とつけてやる。

クロージャ(無名関数)
最近全然JS書いてないけど、スコープを作るために
無名関数書くっていうのもありますよね。

クラス内の定数
const 定数名 = 値;
グローバルな定数とは書き方が違う。
しかも$マークは付けない。
自クラス内で使う場合は、self::定数名
Javaでのstaticと同じような扱いか。

PHP 5.3 以降のconst
クラスの定数かどうかに関わりなく、定数宣言にconstが使えるそうです。
同じかと思ったら、下記の違いがありました。
constで定義したクラス外の定数 = 名前空間に属する
defineで定義した定数 = グローバルな定数

変数名と定数名と関数名
1文字目 = _または半角英字
2文字目以降 = _と 半角英数字
大文字・小文字を区別する。
※関数名のみ大文字・小文字を区別しない
※そうは言っても「書いた通りの大文字小文字で呼出せよ」と公式ドキュメントには書いてある。

PHPのfor文は変化式を複数かける
まぁforのスコープの中で増やしている処理がすっきり書けるっていうだけですが、
for ( $i = 0 ; $i < 0 ; $i++ , $countDown-- )
という書き方が可能。カンマ区切りで複数の処理を書くことができます。

PHP は関数のオーバーロードをサポートしていません。
公式ドキュメント
Qiitaの記事で紹介されていますが、
実装でカバーできるようです。

NULLとNULL文字(\0・NUL)は同義ではない
NULL文字(\0)の存在を初めて知りました。
文字列の終端を表すための文字なんですね。
一方NULLは何も参照していないことを表す記号ですね。

100-200回を超える再帰呼び出しはするな
これも公式ドキュメントネタです。
Paizaさんみたいなコードクイズでもない限り、自分は再帰処理を滅多に書きませんが、
メモリがスタックする可能性があることは記憶の片隅に留めたい。

PHPの変数は値を格納する「箱」not label
変数Aに変数Bを代入する場合、変数Bの値をコピーするということになる
$a = 10;
$b = $a;
$b = 20;
最後に$bに20を代入しているけど、$aの値は10のまま

逆に2つの変数を連動したい場合
参照を渡してみる
複数回メソッドを呼び出す際や、スコープをまたいで値を変更してあげたいときに
参照渡しを使う
&アンパサンダをつける。 変数の初期化
$a = 10;
$b =& $a;
$b = 20;
最後に$bに20を代入すると、$aも20となる

変数の初期化
 function doubleUp(&$num) {
   $num *= 2;
 }

 $age = 20;
 doubleUp($age);

doubleUpを呼ぶと、引数に渡した変数が倍に設定される。

アクセス修飾子(再掲)
デフォルトなんだったか忘れる。。。。publicですね。
public, protected, private
privateは自クラスのみアクセス可、子クラスからもアクセス不可。
protectedは自クラスと子クラスからアクセス可。
publicはどこからでもアクセス可
varを使ってプロパティを宣言した場合や、メソッドにアクセス権を明記しない場合は、public扱いです。

UTF8 BOM
BOMとか初めて知った。。。
Byte Order Mark
符号化に関するファイルヘッダーで、これが付いていることにより、 想定外の動作になることがあるらしい。

PDO_DSN
DSNはData Source Nameの略みたいです。
詳しくは公式ドキュメント参照ですが、
mysql:host=xxx;port=xx;dbname=xxx
というようにsql名:key=value;..で組み立てた文字列を使う。

PDO::setAttribute
属性の設定
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
で、エラー時に例外を投げる設定になる。その他は公式参照。

PDO::setAttribute( ATTR_EMULATE_PREPARES, false )
属性の設定
SQLインジェクション対策として、常にfalseにしましょう
で、エラー時に例外を投げる設定になる。その他は公式参照。
また、true担っているとDBでint型のものをStringに変換してしまうとか。。。
Qiita PDOでATTR_EMULATE_PREPARESを適切に設定してないとSQLインジェクションの原因になるかも(MySQL編)
参照:なんでPHPはMySQLからのリザルトがint型のはずなのにstring型になってしまうん?

MySQLとPHP/基本のメモ2

続きです。


メモ

ユーザ一覧表示
> SELECT user, host FROM mysql.user;
前回も載せたんですけどね。覚えてなかったので。
mysqlというシステム用のスキーマがあり、そこにuserテーブルがあると。

ユーザの削除
> drop user dbuser@localhost;

PHP Data Objects(PDO)
PHPでDBへつなぐ時のインターフェース。コネクターのことかな。

変数名の_アンダースコア
人気があるコーディング規約
プロパティの変数名の頭に_をつけることで、thisをつけなくても(つけ忘れても)
プロパティとわかりやすくする。また、そうすることで変数名の重複を減らすことができる。

ヒアドキュメント内の変数
展開される
シェルスクリプトとはちがうみたい

define('key' , 'value);
定数の設定。Javaと違いすぎて忘れる。

PDOのテンプレ
まず、DB名やユーザ名・PWを定数定義するとして、
try {
  // connect
  $db = new PDO(PDO_DSN, DB_USERNAME, DB_PASSWORD);
  $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  // proc
  $db->exec("insert into users (name,score) values ('hoge', 5);");
  echo "user added!";


} catch (PDOException $e) {
  echo $e->getMessage();
  exit;
}

error
SQLSTATE[42000]: Syntax error or access violation: 
1064 You have an error in your SQL syntax; 
check the manual that corresponds to your MySQL server version 
for the right syntax to use near 
'insert555 into users (name,score) values ('tag', 5)' at line 1

preppare()
複数回使うクエリに適している。SQLインジェクションの対策が必要。
  $stmt = $db->prepare("insert into users ( name , score ) values ( ? , ? );");
  $stmt->execute(['hoge', 100]);
  echo "insert no : " . $db->lastInsertId();

exec()
結果を返さないで実行する。selectなど。
安全なクエリに使う。

query()
結果を返す。
安全、かつ、一度しか実行されないようなクエリに使う。
下記の例は2次元配列として格納されるようです。(3つの要素を持つ連想配列の配列)
  $stmt = $db->query("select * from users");
  $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
query()の結果は、PDOStatement オブジェクトが返ります。 詳しいことはQiitaのこの記事を読んでください。

$db->lastInsertId();
最後に挿入されたレコードのIDを返します。

名前付きパラメータ
「:パラメータ名」とすることで連想配列みたいに扱える。
  $stmt = $db->prepare("insert into users ( name , score ) values ( :name , :score );");
  $stmt->execute([':name'=>'hoge', 'score'=>100]);
:を付けても付けなくてもアクセスできました

bindValue()
プレースホルダーに値を保持させたままにすることができる。
下記の例だと$nameは変えてないので、hogeでちがうscoreのレコードを2行挿入できる。
  $stmt = $db->prepare("insert into users ( name , score ) values ( ? , ? );");

  $name = 'hoge';
  $stmt->bindValue(1, $name, PDO::PARAM_STR);
  $score = 43;
  $stmt->bindValue(2, $score, PDO::PARAM_INT);
  $stmt->execute(); // 1st
  $score = 55;
  $stmt->bindValue(2, $score, PDO::PARAM_INT);
  $stmt->execute(); // 2nd


プレースホルダーに名前を付けるとこうなる。
  $stmt = $db->prepare("insert into users ( name , score ) values ( :name , :score );");

  $name = 'hoge';
  $stmt->bindValue('name', $name, PDO::PARAM_STR);
  $score = 43;
  $stmt->bindValue('score', $score, PDO::PARAM_INT);
  $stmt->execute(); // 1st
  $score = 55;
  $stmt->bindValue('score', $score, PDO::PARAM_INT);
  $stmt->execute(); // 2nd

その他のデータ型
PDO::PARAM_NULL
PDO::PARAM_BOOL

bindParam();
プレースホルダーが参照する変数を固定する
  $stmt = $db->prepare("insert into users ( name , score ) values ( :name , :score );");

  $name = 'hoge';
  $stmt->bindValue('name', $name, PDO::PARAM_STR);

  $stmt->bindParam('score', $score, PDO::PARAM_INT);
  $score = 100;
  $stmt->execute();
  $score = 400;
  $stmt->execute();

FETCH_CLASS
PDOオブジェクトをクラスに代入する
Userクラスを作った上で、FETCH_CLASSするとオブジェクトを配列で返す。
class User {
# public $id;
# public $name;
# public $score;
  public function show() {
    echo "$this->name ($this->score) <br>\n";
  }
}

  $stmt = $db->query("select * from users");
  $users = $stmt->fetchAll(PDO::FETCH_CLASS, 'User');
プロパティは書かなくても、PDOのフィールドが勝手に保持されるみたいです。
楽だけどバグに気づかなそうなので、明示すべきですかね。

$stmt->rowCount()
PDOオブジェクトが持つ行数(要素数)を返す。

$db-beginTransaction();
トランザクション開始

$db->commit();
トランザクション終了

$db->rollback();
ロールバック
PDOExceptionをキャッチさせて使う。

2016年12月25日日曜日

MySQL/基本のメモ

PHPの基礎文法をおさらいできたところでMySQLも基本を振り返ってみます。


メモ

ログイン
$ mysql -u USER [-p]
-pを入れるとパスワードを入力することができる。

ログアウト
> exit;
OR
> \q

ヘルプ
\h OR help

標準入力のクリア
\c

DBの作成と作業ユーザへの権限付与
> set password for root@localhost=password('xxx'); -- rootユーザのパスワード設定
> create database store; -- DBの作成
> show databases; -- DBの一覧表示
> grant all on store.* to dbuser@localhost identified by 'xxx'; -- 作業ユーザの作成と権限付与
> SELECT user, host FROM mysql.user; -- ユーザ一覧表示
> use store; -- DBへの接続

テーブルの作成
> create table users (
-> id int,
-> name varchar(255),
-> email varchar(255),
-> password char(32),
-> score double,
-> sex enum('male', 'female'),
-> memo text,
-> created datetime
-> ); -- table作成
> show tables; -- table一覧表示

テーブルのコピー
> create table new_users like users; -- テーブル名だけ違う、同じ構造のテーブルを作成

NULL制約
id int not null

UNIQ制約
email varchar(255) unique

連番
id int auto_increment
連番を振るカラムにはインデックスを張る必要がある。
その際、primary key / keyのどちらでも問題ない。

default
score double default 0.0

主キー
id int primary key

主キーでないところにインデックスを貼る
key score (score)

tableのインデックスの確認
> show indexes from TABLE_NAME;

tableの構造を表示
desc[ribe] TABLE_NAME;

列の追加
> alter table users add created datetime default CURRENT_TIMESTAMP ;

indexの追加
> alter table users add index name(name);
インデックス名(カラム名)

indexの削除
> alter table users rename system_users;

tableのリネーム
> alter table users drop index name;

DBの削除
> drop database store; -- DBの削除

扱えるデータ型
  • 数値:int, double
  • 文字列:char, varchar, text
  • 日付:date, datetime
  • その他:enum

レコードを帳票形式(項目を横ではなく縦に並べる方式)で出力する
select * from users \G
\Gで文が終わるみたいです。;セミコロンを続けて末尾に入れたら、空行だと怒られた。
select * from users \G;
ズラズラ
...
ERROR:
No query specified

limit / offset。上から2行を無視し、3行取得。
「limit 3 offset 2」「limit 2 ,3」のどちらでもいい。
パラメータが逆になるので注意

外部ファイルからSQLを実行
$ mysql -u dbuser -p store < dataInit.sql

バックアップファイルの作成
$ mysqldump -u dbuser -p store > store.bu.dump

バックアップファイルからの復元
$ mysql -u dbuser -p store < store.bu.dump