PHPでのクラス定義とJavaScriptでのクラス定義を対比させてみた

## はじめに前置き

CakePHPなどでWebアプリケーションを書いてて、JavaScript側のコードが思ったように書けずに苦労するケースが割りとあるのかなと思ってます。

その要因となるものは色々あると思うのですが、考えられるものの１つとして、PHPでのクラス定義とJavaScriptでのクラス定義とがうまく対比できない所にあるのかなと思って、参考になる情報がないかググってみました。

[PHPとJavaScriptにおけるオブジェクト指向を比較する](http://www.slideshare.net/kwatch/phpjavascript)というスライドは情報はとてもまとまってるのですが、自分が探していたそれぞれの言語でのクラス定義の方法を対比させるようなコード例が出ておらず、しかたがないので自分でコードを書いて対比させて折角なのでドキュメントにまとめることにしました。

### 注意

- JavaScriptでのクラス定義の方法は色々なアプローチがあると思うのですが、自分がなれ親しんでるCoffeeScriptで生成されるJavaScriptのクラスをサンプルとして活用してます。
- PHPほとんど書いたこと無いのでPHPでのクラス定義が適切で無い可能性あるのでツッコミお願いします

### 確認した環境

- Mac OS X 10.9.5
- PHP
    - PHP 5.4.30 (cli) (built: Jul 29 2014 23:43:29)
- JavaScript
    - Node.jsで確認
    - v0.10.13

## 基本的なクラス定義の方法

メンバー変数に**message**を持った**SimpleClass**クラスというものを考えてみました。

### PHPの場合

```php
class SimpleClass {
  public $message = 'Public';
}
```
となるかと思います

### JavaScriptの場合

```javascript
var SimpleClass;
SimpleClass = (function(){
  function SimpleClass() {
    this.message = 'Public';
  }
  return SimpleClass;
})();
```

という形になります。

### 参考まで上記のJavaScriptを生成したCoffeeScript

もしかしたらPHPを書き慣れてる方にはCoffeeScriptの方が意図が伝わりそうな気がするのでCoffeeScriptでのコードも書いておきます

```coffee
class SimpleClass
  constructor:() ->
    @messsage = 'Public'
```


## インスタンス化してパブリックな変数をターミナル上に表示する

### PHPの場合

newしてインスタンス化した上で、メンバー変数を以下のようにして呼び出すことが出来ます

```php
class SimpleClass {
  public $message = 'Public';
}
$obj = new SimpleClass();
print $obj->message; 
```

### JavaScriptの場合

クラス定義はちょっと違和感があるかもしれませんが、メンバー変数を呼び出す方法はPHPのそれとあまり大差がないかと思います。

```javascript
var SimpleClass;
SimpleClass = (function(){
  function SimpleClass() {
    this.message = 'Public';
  }
  return SimpleClass;
})();
var obj = new SimpleClass();
console.log(obj.message);
```

### 参考まで上記のJavaScriptを生成したCoffeeScript

CoffeeScriptの場合にも大差がないと思います

```coffee
class SimpleClass
  constructor:() ->
    @messsage = 'Public'
      
obj = new SimpleClass()
console.log(obj.message)
```

## パブリックなメソッドを定義する

さて今度は**printHello**というパブリックなメソッドを定義してみましょう。

### PHPの場合

PHPの場合には以下のようになるかと思います。

```php
class SimpleClass {
  public $message = 'Public';
  public function printHello(){
    print("newしたオブジェクトからは呼び出せる");
  }
}
$obj = new SimpleClass();
$obj->printHello();
```

### JavaScriptの場合

JavaScriptの場合には、クラス名の**SimpleClass**の後に、ドット（.）と**prototype**を付けて、その後にメソッド名を付けます。prototypeの概念説明はやりだすとキリがない（というかそこまで的確に説明する自信がない）ので[このあたり](http://qiita.com/takeharu/items/809114f943208aaf55b3)を読むのが良いのかなと思います。

```javascript
var SimpleClass;
SimpleClass = (function(){
  function SimpleClass() {
    this.message = 'Public';
  }
  SimpleClass.prototype.printHello = function () {
    console.log("newしたオブジェクトからは呼び出せる");
  };
  return SimpleClass;
})();
var obj = new SimpleClass();
obj.printHello();
```

### 参考まで上記のJavaScriptを生成したCoffeeScript

CoffeeScriptの場合、function **printHello(){}**に相当する記述が **printHello:() ->**という形でメソッドを定義します。

※CoffeeScriptのメソッド定義の記法に最初違和感を感じるかもしれませんね

```coffee
class SimpleClass
  constructor:() ->
    @messsage = 'Public'
  printHello:() ->      
    console.log("newしたオブジェクトからは呼び出せる") 
obj = new SimpleClass()
console.log(obj.message)
```

## プライベートな変数とその変数を得るためのメソッドを定義

最後に**msg**というプライベートな変数を定義しつつ、その変数を得るためのメソッドを定義してみましょう。

### PHPの場合

まず、プライベート変数だけ定義してみます

```php
class SimpleClass {
  public $message = 'Public';
  private $msg = 'Private';
  public function printHello(){
    print("newしたオブジェクトからは呼び出せる");
  }
}
```

上記定義した後に

```php
$obj = new SimpleClass();
print $obj->msg;

```

とすると**Cannot access private property SimpleClass::$msg** というメッセージが表示されるかと思います。

名前の通りプライベートな変数なので外部からは直接呼び出せません。
そこで、このプライベートな変数にアクセスできる**getMsg**というパブリックなメソッドを定義します。

```php
class SimpleClass {
  public $message = 'Public';
  private $msg = 'Private';
  function printHello(){
    print("newしたオブジェクトからは呼び出せる");
  }
  public function getMsg(){
      print($this->msg);
  }
  
}
```

上記のようにした上で、以下のようにgetMsg()を通じて、SimpleClassクラスの中で定義されてるプライベートな変数にアクセスして画面表示されます

```php
$obj = new SimpleClass();
$obj->getMsg();
```


### JavaScriptの場合

以下のようにすることで、プライベートな**msg**変数を定義できます。パブリックな変数を定義した際には、this.xxxとしましたが、プライベートな変数の場合には、JavaScriptの変数スコープが関数単位である特徴を活かして以下のようにしてあげればプライベートなものとして利用できます。

```javascript
var SimpleClass;
SimpleClass = (function(){
  var msg = 'Private';
  function SimpleClass() {
    this.message = 'Public';
  }
  SimpleClass.prototype.printHello = function () {
    console.log("newしたオブジェクトからは呼び出せる");
  };
  return SimpleClass;
})();
```

上記定義したものに対して

```javascript
var obj = new SimpleClass();
console.log(obj.msg());
```
とすると、以下のようにエラーになります。

```sh
console.log(obj.msg());
                ^
TypeError: Object #<SimpleClass> has no method 'msg'
```

プライベートな**msg**にアクセスするために、getMsg()メソッドを定義するには以下のようにします。

```javascript
var SimpleClass;
SimpleClass = (function(){
  var msg = 'Private';
  function SimpleClass() {
    this.message = 'Public';
  }
  SimpleClass.prototype.printHello = function () {
    console.log("newしたオブジェクトからは呼び出せる");
  };
  SimpleClass.prototype.getMsg = function () {
    console.log(msg);
  };  
  return SimpleClass;
})();
```

上記定義したものに対して以下のようにすると、画面上に**Private**という文字が表示されます

```javascript
var obj = new SimpleClass();
console.log(obj.msg());
```

## 終わりに

JavaScriptでのクラス定義は、最初なれないと違和感があると思いますし、実際自分も正直、このあたりを素でサクッとは書けません(^_^;)

自分の場合には、Rubyを割りとずっと勉強していたこともありクラス定義については、CoffeeScriptのチカラを借りながらコードを書いていたことでこのあたりの定義については理解が進んだので、そういうのを使いながら、PHPでのそれと近いものを自分なりに見つけながらコードを書いていくのがよいのかと思います。

また[JavaScript: The Good Parts](http://www.amazon.co.jp/exec/obidos/ASIN/4873113911/hoyamada-22/ref=nosim/)あたりの本を読むと、JavaScriptのクラス定義についてより理解が進みやすくなると思います。