JavaとPHPの文法比較

こんにちは、スパイシーチキン弁当に慣れてきつつある浦本です。

今回はJavaとPHPの文法を比較し、何が同じで何が違うかを説明します。
Java開発者にとってはPHP入門になりますし、
PHP開発者にとってはJava入門になります。

(追記:というよりはPHPプログラミングで気をつけたい点として読んでいただければ、幸いです。)

■まずは共通点から

クラスの継承
PHPとJavaのどちらも、同時に1つの親クラスを継承できます。
extendsの書き方も同じです。


class Hoge extends SuperHoge { ... }

抽象クラス、抽象メソッド
抽象クラス、抽象メソッドの意味は同じです。
PHPもJavaも同様に、abstractキーワードを付けます。

インターフェイスの実装
PHPとJavaのどちらも、同時に複数のインターフェイスを実装できます。
implementsの書き方も同じです。


class Hoge implements IFoo, IBar { ... }

extendsと組み合わせる場合も、書き方は同じです。


class Hoge extends SuperHoge implements IFoo, IBar { ... }

インターフェイスの用語自体も、同じ意味です。
インターフェイスには、abstract publicメソッドと、定数のみ定義できます。

■異なる点

例外処理
PHPとJavaのどちらも、try-catch文の書き方と処理の流れは同じですが、以下の2点が違います。
・PHPにはチェック例外がなく、throwsを書けない
・PHPにはfinallyがない

PHPの例外処理で最も残念なのは、チェック例外という仕組みがなく、throwsを書けないことです。
(もちろんthrowは書けます。throwsが書けないのです。)

Javaでは、RuntimeException以外のExceptionのことを、チェック例外(checked exception)と呼びます。
あるメソッド内でチェック例外をthrowする場合、
「メソッド内でcatchするか、throwsでメソッドの外に投げるか」しないとコンパイルが通りません。
その仕組みによって、catchの書き忘れを防ぐことができ、throwsによってそのメソッドがどんな例外を投げるのか明示できるのです。これは強力な機能と言えます。

チェック例外のサンプル1 (コンパイルが通らない)


// Java
public class Hoge {
  
  public void hogeMethod1() {
    // コンパイルエラー。
    // メソッド内でcatchするか、throwsでメソッドの外に投げないと絶対ダメ。
    throw new Exception("例外発生!");
  }
  
  public void hogeMethod2() {
    // これは非チェック例外なので、
    // catchしなくても、throwsを書かなくてもコンパイラは文句を言わない。
    throw new RuntimeException("例外発生!");
  }
  
}

チェック例外のサンプル2 (catchしたのでコンパイルが通る)


// Java
public class Hoge {
  
  public void hogeMethod1() {
    try {
      throw new Exception("例外発生!");
    } catch (Exception ex) {
      // 例外処理する
    }
  }
  
  public void hogeMethod2() {
    throw new RuntimeException("例外発生!");
  }
  
}

チェック例外のサンプル3 (throwsで外に投げる例外を明示したのでコンパイルが通る)


// Java
public class Hoge {
  
  public void hogeMethod1() throws Exception {
    throw new Exception("例外発生!");
  }
  
  public void hogeMethod2() {
    throw new RuntimeException("例外発生!");
  }
  
}

サンプル3のhogeMethod1()を別メソッドから呼び出す場合も、
catchするかthrowsを書くかしないと、コンパイルが通りません。
実に安心ですね。

PHPではチェック例外の仕組みがサポートされていませんので、
コメント中にどんな例外を投げるか書いておくことしかできません。
PHPの場合、try-catchを書くかどうかは、
完全にメソッドの利用者任せになってしまいます。

なお、PHPにはfinallyブロックがありません。
finallyブロックとは、try-catchの後に必ず実行される後処理を書くブロックです。
finallyが無いのはやや不便ではありますが、
チェック例外が無いことに比べると些細な違いです。

変数名
PHPでは変数名の頭に$マークを付けます。Javaでは付けません。
PHPのように$が付いている場合、それが変数だと一目で判別できる半面、変数を参照する箇所で文字数が増えます。
これについては、慣れればどちらでもOKといった感じです。

変数の型
PHPでは変数の型指定ができず、どんな型でも代入できます。
Javaでは変数を宣言するときに必ず変数の型を指定するため、
互換性のある型(同じ型かその子孫)のみ代入できます。


$hoge = new Hoge();  // PHP
Hoge hoge = new Hoge();  // Java

変数の型が決まっていれば余計なバグの心配が無くなるので、
Javaのような静的型付け言語は安全と言えます。
なぜなら、「明らかな型の矛盾」を含むコードはコンパイルが通らないからです。

引数の型
PHPではなぜか、メソッド(と関数)の引数だけは型指定が可能です。
ただしクラス型とarray型の場合のみです。intなどは無理です。


// PHP
class Hoge {
  public function hogeMethod(Fuga $fuga) {
    return $fuga->fugaMethod();
  }
}

Javaでは当然、メソッドの引数には型指定が必要です。

返り値の型
PHPでは、メソッド(と関数)の返り値の型指定はできません。
それゆえに、メソッドの利用者に無用な心配を与えてしまいます。
なぜならば、どんな型でも返すことができますし、
returnしたりしなかったりできるからです。

Javaでは当然、メソッドの返り値には型指定が必要です。
メソッド名の前に、返り値の型を書きます。

メソッドへのアクセス
PHPでは「->」や「::」を用います。
Javaでは「.」で統一されていますので、タイプが楽です。

インスタンス・メソッドの場合


$obj->method();  // PHP
obj.method();  // Java

クラス・メソッドの場合


Hoge::staticMethod();  // PHP
Hoge.staticMethod();  // Java

■まとめ
PHPの文法にはまだまだ改善の余地があり、今後に期待したいところです。
それにしても、比較について書くのは以外に大変ですね。
他にも、オーバーライドやパッケージなど相違点は色々あるのですが、今回はこれくらいでご勘弁を。

ちなみに普段Javaをお使いで、PHPによる楽チン開発にご興味のある方は、
symfonyフレームワークが便利でオススメですよ。
チュートリアルも充実してます。
http://www.symfony-project.org/gentle-introduction/1_4/en/

■参考文献
Javaの例外処理は以下の本が参考になります。Addison Wesleyは深い本が多いですね。
Nigel Warren and Philip Bishop
『Java in Practice: Design Styles and Idioms for Effective Java』