thumbnail

PHP・JavaScript・Pythonの紛らわしい仕様の違いまとめ【比較】

複数の言語を同時に書いていると、言語の仕様や関数名の違いから混乱することもあると思います。個人的に、PHPとJavaScriptを並行して書くことが多くなってきたので、両者の書き方の違いについてまとめました。この記事は2回に渡ってまとめる予定で、今回はPHPとJavaScriptの「仕様の違い」についてです。

比較演算

左辺と右辺、2つのオペランドが等しくなる条件。
つまり、A==B、A===Bの判定条件の仕様の違いです。

クラス(インスタンス)の比較

trueになる条件は以下のとおりです。

演算PHPJSPython
等価(==)同じクラスのインスタンスで同じプロパティを持つ参照が同じ参照が同じ
厳密等価(===)参照が同じ参照が同じ

連想配列(PHP)とオブジェクト(JS)、ディクショナリ(Python)の比較

連想配列とオブジェクトを比較するのはナンセンスですが、「キー : 値」という同じ機能を提供するためここで比較します。trueになる条件は以下のとおりです。

演算PHP(連想配列)JS(オブジェクト )Python(ディクショナリ)
等価(==)同じ要素を持つ参照が同じ同じ要素を持つ
厳密等価(===)同じ要素を持ち並び順も同じ参照が同じ

PHPの連想配列と配列は内部的には同じなので、上記のことは配列にも成り立ちます。

代入演算

変数に値を代入するとき、値渡しになるか。参照渡しになるか、ということです。

配列の代入

PHPJSPython
値渡し参照渡し参照渡し

クラス(インスタンス)の代入

PHPJSPython
参照渡し参照渡し参照渡し

PHPで値渡しにしたい場合はclone命令を使います。

関数の引数に配列を渡す

関数に引数として渡す配列は、値渡しになるか、参照渡しになるか、ということです。

PHPJSPython
値渡し参照渡し参照渡し

PHPには参照(&)があるので、それを踏まえれば値渡しがデフォルトであることを忘れにくいと思います。

switch文

式と値の比較方法です。等価か厳密等価か言語によって違います。

switch ($num) {     //この変数$num(式)と
  case 1:         // caseの値1を、式 == 値 と判定するのか、 式 === 値 と判定するのか
}    
PHPJSPython
等価演算(==)厳密等価演算(===)switch文なし

PHP8で導入されたmatch式は厳密等価演算です。

スコープ

グローバル変数とローカル変数の扱いも異なります。

PHPJSPython
・スコープが異なれば異なる変数。
・ローカルに変数宣言がない場合、ローカルでグローバル変数を使おうとしてもローカル変数として扱われる。(そもそも警告が出る)
・グローバル変数として扱いたいならglobal命令を使う。
・ローカルに変数宣言がない場合、ローカルでグローバル変数を自動参照する。
・ローカルで書き換えた値はグローバルにも反映される。
・スコープが異なれば異なる変数。
・ローカルに変数宣言がない場合、ローカルでグローバル変数を使おうとしてもエラーが出る
・グローバル変数として扱いたいならglobal命令を使う
・ブロックスコープがない。ローカル変数になるのは関数の中のみ



<?php
//グローバル
$x = 1;

//ローカル
function hoge() :int {
  return ++$x; //グローバル変数xとは別物
}

hoge();

echo $x; // 1のまま
//グローバル
let x = 1

//ローカル
function hoge() {
  return ++x // グローバル変数xを参照する
}

hoge()

console.log(x) // 2になる
a = 10
def hoge():
  global a #aをグローバル変数として扱う時、global宣言がないとエラー
  # a = 10 と新しく代入するとローカル変数になりエラーは出ない
  a += 20
hoge()

print(a) #グローバル変数として使ったので30となる

PHPやPythonにはglobal宣言があることを踏まえれば、この仕様は忘れにくいと思います。

配列の仕様

最大インデックス以上のインデックスに代入した場合

配列の長さがnのとき、nより大きいインデックスmに、ary[m] = xxx のように値を代入した場合の挙動が違います。

//長さ3の配列
//最大インデックスは2
$ary = ['taro', 'jiro', 'saburo'];

//大きいインデックスに代入
$ary[100] = 'hoge';
PHPJSPython
インデックスmに値が追加される。
長さはn+1(プラス1)。
n ~ m-1のインデックスの値は定義されない。
インデックスmに値が追加される。
長さは+1(プラスm-n+1)。
n ~ m -1にはundefinedで埋め尽くされる。
エラーが出てそもそも代入できない

コードの例では n = 3、m = 100と置き換えて考えてください。

ネストされたfor文からの脱出

PHPJS
break nbreak ラベル
<?php
for ($i = 1; $i <= 9; $i++) {
  for ($j = 1; $j <= 9; $j++) {
    echo $i * $j . '<br>';
    if ($i * $j === 21) {
      break 2; //2階層抜ける
    }
  }
}
label:
for (let i = 1; i <= 9; i++) {
  for (let j = 1; j <= 9; j++) {
    console.log(i * j)
    if (i * j === 21) {
      break label;
    }
  }
}

クラスの記述

コンストラクタ

PHPJSPython
public function __construct(引数)constructor(引数)def __init__(self, 引数)

親コンストラクタの呼び出し

PHPJSPython
parent::__construct(引数)super(引数)super().__init__(引数)

親メソッドの呼び出し

PHPJSPython
parent::メソッドsuper.メソッドsuper().メソッド

まとめ

個人的に忘れがちな部分についてだけまとめました。
次回の記事では、配列の操作についてまとめます。