#前書き
筆者自体PHP初心者ですが、コメント欄と併用してしっかりとした基礎をまとめているシートにできると思いますので、玄人の方は、間違っていたらコメント欄へご指摘願います。
##自己紹介
Twitter @konojunya
じゅんじゅんというニックネームで、関西を拠点に活動しているフロントエンドエンジニアです。
HAL大阪の新2回生です👍 (2016.4.18現在)
よくstart up系イベントに行くので、大阪らへんの方は会いましょう!
では、早速。
#初めてのPHP
順番にPHPを攻略していきたいと思います。
##環境
筆者はPHP v5.5でやっています。
phpをインストールして、Webサーバ(Apacheなど)にあげれば動きます。
ローカル開発環境は
vagrantを用いたPHPの環境構築
などをご覧ください。
PHPは、.php
ファイルに
<?php
//insert code...
?>
で、書くことができます。
早速PHPに入っていきたいと思います。
##変数
PHPでは、型の宣言がなくJavaScriptのようなvarもありません。(フレームワークとかは知らん!!)
最初に$
をつけて変数を宣言します。
$msg = "Hello World";
echo $msg;
$msg
という変数に、文字列の"Hello World"
を代入した形です。
echo
を使う事で、変数を展開してWEBページへ出力してくれます。
この時の$msg
の型はString型ですね。
PHPが扱う型には以下のようなものがあります
- 文字列を扱う
- string
- 数値を扱う
- int
- float
- 真偽値(true / false)
- boolean
- 配列
- オブジェクト
- null(何もない)
型などはvar_dump
などを用いて簡単に確認できます
$msg = "Hello World";
var_dump($msg);
##定数
先ほどの変数は、後からでも変更可能な箱でした。
定数は、一度定義すると後から変えることのできないものになっています。
定数を定義するときはdefine
というキーワードを使います。
define("PI",3.141592);
echo PI;
この時に注意したいのが、$
がいらないということと
定数を定義するときは全部大文字にするのが、デファクトスタンダードだということです。
このPI
は定数なので、後から
PI = 3;
のようなゆとり教育は許さないということです。
なお、定数には幾つか最初から定義されているものがあります。
var_dump(__LINE__); //今の行数
var_dump(__FILE__); //そのファイルまでのパス
var_dump(__DIR__); //ディレクトリのパス
##文字列
文字列は"ダブルクォーテーション"
か'シングルクォーテーション'
で囲むことで、扱うことができます。
この差は、そのクォーテーションの中で、変数が展開できるか否かです。
$name = "konojunya";
echo "My name is $name";
こうすることで、ダブルクォーテーションの中で、変数を展開できます。
なお、変数の展開は、もっとわかりやすく書くこともできます。
$name = "konojunya";
echo "My name is $name";
echo "My name is ${name}";
echo "My name is {$name}";
これはすべて同じ出力結果になります。
では、シングルじゃないとダメな時どうするのか。
##文字列の連結
変数を展開したものと、文字列を連結させれば、同じことができます。
$name = "konojunya";
echo 'My name is '.$name;
PHPでは.(ドット)
を使うことで、連結ができます。
##配列
似たようなデータを一つの名前で管理したい時に使えるのが、配列です。
$colors = array("red","blue","yellow");
PHP5.4以上なら、[]
で置き換えることができます。
$colors = ["red","blue","yellow"];
この場合、例えばredを出したい場合
echo $colors[0];
先頭から、0..1..2..3..と続いているので、redは0番目。
大カッコに添字で、取り出せます。
これでは、データを取り出しにくいので、先人は名前をつける機能をつけてくれました。
##連想配列
書き方を見てみましょう
$members = [
"jun" => "konojunya",
"hoge" => "hogehogeo"
];
取り出し方も簡単になっています。
echo $members["jun"]; //konojunya
##ループ&条件分岐
ループ(for,while)と条件分岐(if,switch)は、他の言語と変わらないので省きます。
PHPでは、HTMLに埋め込むことがよくあると思います。
そこで
?><ul>
<?php for($i=0;$i<10;$i++){ ?>
<li><?php echo $i ?></li>
<?php } ?>
</ul>
と書くのは、見づらいので、コロン構文というものを使い書き換えることができます。
?><ul>
<?php for($i=0;$i<10;$i++): ?>
<li><?php echo $i ?></li>
<?php endfor; ?>
</ul>
初めの波カッコを:
に変えて、終わりの波カッコをend〇〇
に置き換えることができます。
##関数
関数は、複数の処理を一つにまとめてくれるものです。
関数は、引数と戻り値が存在します。
まず単純にHello World
をecho
するhello関数を作りましょう
function hello(){
echo "Hello World";
}
hello(); //Hello World
その他の言語と同じですね。function
を使って、関数を定義します。
では、名前を引数にとった場合どうなるか。
function hello($name){
echo "Hello ${name}";
}
hello("junya"); // Hello junya
junya
を$name
に代入して、使っています。
なお、この$name
はこのhello関数の中だけで使えるローカル変数になります。
この関数の外から$name
にアクセスはできません。
戻り値を使った場合はどうなるでしょうか。
function hello($name){
return "Hello ${name}";
}
echo hello("junya"); // Hello junya
return
というキーワードで、その関数から値を返すことができます。
##クラス
クラスというのは、設計図とよく言われています。
何回も同じようなものが登場する場合は、このクラスを使った方が良いとされています。
書き方を見てみましょう。
では、ユーザーを管理するUser
クラスを作りましょう。
class User{
//property
public $name;
//constructor
public function __construct($name){
$this->name = $name;
}
//method
public function sayName(){
echo "Hello $this->name !";
}
}
クラス名は最初が大文字という決まりがあるので注意しましょう。
クラスは、property
、constructor
、method
を持ちます。
property
は、そのクラスが持つ値です。
constructor
は、そのクラスがインスタンス化される時に絶対呼ばれるものです。
method
は、そのクラスが持っている関数だと思ってください。
このUserクラスは、$name
というプロパティを持っています。
インスタンスする際に、constructorによってその$nameに引数で入ってきたものが代入されます。
インスタンスするには、new
というキーワードを使います。
$junya = new User("junya");
これで、$junya
は、自分の名前や、sayName()が使えます。
自分の名前にアクセスするには
echo $junya->name;
sayNameを使えば
$junya->sayName();
という風に使えます。
##クラスの継承
クラスを作る際に、さっきのクラスに似てるけどここで差別化してるし、、
ちょっと違う挙動をさせたい。。
みたいなものがあったとして、そのクラスをまた1から書くのはあまり、よろしくないです。
そんな時に、前作ったクラスを引き継いで新しいものを作るクラスの継承が便利でしょう。
さっき作ったUserクラスを継承させて、SpecialUserというクラスを作ります。
class User {
public $name;
public function __construct($name){
$this->name = $name;
}
public function sayHi(){
echo "Hello $this->name !";
}
}
class SpecialUser extends User {
public function saySpecialHi(){
echo "I am Special $this->name";
}
}
SpecialUserクラスを作るのに、Userクラスを継承するには、
extends
を使います。
これで、SpecialUserクラスは独自のメソッドも使えますが、Userクラスのものも使えます。
SpecialUserをインスタンスする際も
$junya = new SpecialUser("junya");
で、大丈夫です。
この時できたSpecialUserはUserを継承しているので、
SpecialUserが子クラス。Userが親クラスと言います。
over ride
ここで、UserクラスにあるsayHi
メソッドをSpecialUserクラスでも書くとどうなるのでしょうか。
class User {
public $name;
public function __construct($name){
$this->name = $name;
}
public function sayHi(){
echo "Hello $this->name !";
}
}
class SpecialUser extends User {
public function sayHi(){
echo "I am Special $this->name";
}
}
このようにすると
$junya = User("junya"); //Userクラス
$kono = SpecialUser("kono"); //SPUserクラス
$junya->sayHi(); // Hello junya
$kono->sayHi(); // I am Special kono
同じメソッドなのに、スペシャルなkonoくんとパンピなjunyaでは挙動が違います。
これをover rideと言います。
単純に「上書き」です。
このover ride便利ですが、して欲しくない場合もあると思います。
この時に使えるのがfinal
というキーワードです。
さっきのUserクラスのsayHiをfinalを使って、over rideできないようにしましょう。
class User {
public $name;
public function __construct($name){
$this->name = $name;
}
final public function sayHi(){
echo "Hello $this->name !";
}
}
class SpecialUser extends User {
public function sayHi(){
echo "I am Special $this->name";
}
}
Userクラスにfinal
をつけることで、SpecialUserのsayHiメソッドはover rideに失敗するので、
エラーになると思います。
そろそろアクセス権を見ていきたい時期ですね。
##アクセス権
今まで、クラスの中に出てくるpublic
ですね。これがアクセス権です。
アクセス権には次の3つがあります。
- public
- protected
- private
- public
publicは、全域からアクセスが可能
- protected
protectedは、親子クラスとクラス内からのみアクセス可能
- private
privateは、クラス内からのみアクセス可能
に、なっています。
class User {
public $name;
public function __construct($name){
$this->name = $name;
}
public function sayHi(){
echo "Hello $this->name !";
}
}
class SpecialUser extends User {
public function sayHi(){
echo "I am Special $this->name";
}
}
この状態では、Userクラスの$name
はpublicで宣言しているため
インスタンス化した$junya
からも$junya->name
でアクセスできました。
これを
class User {
private $name;
public function __construct($name){
$this->name = $name;
}
public function sayHi(){
echo "Hello $this->name !";
}
}
class SpecialUser extends User {
public function sayHi(){
echo "I am Special $this->name";
}
}
privateにすると、クラス内からはアクセスできますが、そのほかからはアクセスできないので、
SpecialUserの$this->name
もアクセスできませんし、$junya->name
もアクセスできません。
SpecialUserは許可したい、、、、時は、privateをprotectedにしましょう!
##staticについて
staticは、クラスをインスタンス化しなくても、使えるようにする仕組みです。
class User {
public $name;
public static $count = 0;
public function __construct($name){
$this->name = $name;
self::$count++;
}
public static function getMes(){
echo "Hello from static!";
}
}
User::getMes();
$tom = new User("tom");
echo User::$count; //1
staticをつけたメソッドやプロパティはそのクラス名::メソッドなど
でアクセスできます。
Userクラスの中で、自分自身を参照したい場合。
その時はself
を使って、self::$count
のように使っていますね。
##抽象クラス
abstract class BaseUser{ //抽象クラス
public $name;
abstract public function sayHi();
}
class User extends BaseUser{
public function sayHi(){
echo "Hello";
}
}
宣言する際にabstract
というキーワードをつけてあげます。
抽象クラスは、それ自体をインスタンス化することはできません。
抽象クラスのメソッドは、その拡張クラスに実装しないといけないという決まりをもたせることができます。
実装してない場合、エラーになります。
アクセス権なども、抽象クラスに合わせないといけません。
##interface
さて、抽象クラスと似ているものにinterface
というものがあります。
interface sayHi {
public function sayHi(); //interfaceは絶対public
}
interface sayHello{
public function sayHello();
}
class User implements sayHi,sayHello {
public function sayHi(){
echo "Hi!";
}
public function sayHello(){
echo "hello";
}
}
classは、大きくそのものの設計図なのに対して、interfaceはもっと細かい部品部品で見たものという認識をしています。(間違っていたらコメントください。)
interfaceで宣言したものも、クラスの中で実装していかないといけません。
ですが、今までのextends
ではなく、implements
というものを使います。
ここで、大きな違いが、抽象クラスは1つだけど、interfaceは複数同時に追加できるという点です。
なので、より細かい部品(歩く、話す)を作るのにはinterfaceを使い、大部分(人間、生物、車など)を定義するのにクラスを使うのかなぁという具合です。
##外部ファイルの読み込み
では、そろそろ長くなりすぎていませんか?
ファイルを分けて見やすくしていきましょう。
新しく、functions.phpを作ります。
functions.phpには以下の内容があるとします。
function hello(){
echo "Hello";
}
.......
関数を定義しているfunctions.php
をindex.php
で読み込みましょう。
require "functions.php"; // どれか
require_once "functions.php";
include "functions.php";
include_once "functions.php";
この4つでファイルの読み込みができます。
requireとincludeの違いは、
requireは、ファイル名が違うかったりするとエラーが出ます。
includeは、無視してそのまま進みます。
???_onceは、一度読み込んでいればスルー。読んでいなければ読み込むものです。
require "functions.php";
hello();
ライブラリなどもこの方法で、読み込むことができますね。
では、自分の作ったものと他人の作ったものの名前が同じ場合どうすればいいでしょうか。
##名前空間
それを解決してくれるのが、名前空間です。
まずは、使ってみましょう。
functions.phpの最初に
namespace junya\functions;
function hello(){
echo "Hello";
}
のように書きます。
注意しなければならないのが、名前空間の宣言は一番最初にしないといけません。
これをindex.phpで使ってみましょう
// use konojunya\functions as func;
// use konojunya\functions
useを使うことで、その名前空間を使うことができます。
なお、 use konojunya\functions as func
はkonojunya\functionsにfuncという名前をつけてこの中では使うよというものです。
use konojunya\functions
だと、一番最後のfunctionsを取ってくれます。
この名前空間をどう使うのか。
require "functions.php";
use konojunya\functions as func;
func\hello();
このように、その関数の最初に、useで指定した文字をつけます。
これで、ライブラリなどとの衝突を避けることができます。
##例外処理
そろそろ終盤です。
最後に、例外の処理方法について、まとめたいと思います。
例えば、割り算をするdivision()
という関数を作りたいと思います。
function division($num1,$num2){
return $num1 / $num2;
}
echo division(4,2); // 2
この関数の弱点は、$num2
に0が入った場合です。
学校では
function division($num1,$num2){
if($num2 === 0){
return "2つ目に0は指定できません。";
}else{
return $num1 / $num2;
}
}
こんな風にして、まず0が来たらifで弾く。みたいな感じです。
これは、例外処理の書き方で次のように書き直せます。
function division($num1,$num2){
try {
if($b === 0){
throw new Exception("can not use 0");
}
return $num1 / $num2;
} catch (Exception $e) {
return $e->getMessage();
}
}
throwで Exceptionというクラスをインスタンス化したものをcatchに投げているという感じです。
Exceptionは、クラスなので、catchの方で、$eというのに格納してあげます。
そのあと、getMessage()
というメソッドを使うことで、Exceptionをインスタンスするときに、引数に入れた値を取得することができます。
これで、例外処理が来た場合でも、ただのエラーではなく、自分で作ったものに変えることができました。
##あとがき
まだまだPHPは奥が深いですが、基礎の基礎の基礎ということで、今回抑えていきました。
説明が間違えている!などあれば、コメント欄で指摘してください。
至急、これはQiitaの記事を書き変えないと、間違った情報になってしまう!というのがあれば、
Twitter @konojunya へご連絡くだされば、幸いです。。
ホームページ hello world
ありがとうございました!