Perl日記

日々の知ったことのメモなどです。Perlは最近やってないです。

PHPの知見がたまったので共有します

順不同です。

インスタンスメソッド内でのクラス変数取得

<?php
class Hoge {
    public static $ids = array(123, 234, 345);

    public function from_static() {
        return static::$ids; // staticでも
    }

    public function from_self() {
        return self::$ids; // selfでも
    }
}

$hoge = new Hoge();
print_r( $hoge->from_static() ); //=> array(123, 234, 345)
print_r( $hoge->from_self() );   //=> array(123, 234, 345)
  • static::$idsでもself::$idsでもどっちでも呼べる

デフォルト引数に定数値を使う

<?php
const FOO = "fooooo";

function f($w = FOO) {
    return $w;
}

print_r( f() ); //=> fooooo
<?php
class Hoge {
    const ID = 123;

    public function get_id($id = self::ID) {
        return $id;
    }
}

$hoge = new Hoge();
print_r( $hoge->get_id(999) ); //=> 999
print_r( $hoge->get_id() );    //=> 123
  • デフォルト引数には定数値が使える
  • 式は無理

デフォルト引数のnullはタイプヒンティングと併用できる

<?php
function h(array $arr = null) {
    return $arr;
}

print_r( h() ); //=> null

親クラスのメソッドが子クラスのメソッドを呼んでくれる

<?php
class Hoge {
    public function h() {
        return $this->f();
    }

    // どっちが
    public function f() {
        return "Hoge::f()";
    }
}

class Fuga extends Hoge {
    // 呼ばれるの
    public function f() {
        return "Fuga::f()";
    }
}

$fuga = new Fuga();
print_r( $fuga->h() ); //=> Fuga::f()
  • まあそりゃそうだろとは思ったのだが念のため

子クラスのstatic変数を親が呼ぶ(遅延静的束縛)

<?php
class Hoge {
    public static function h() {
        // このクラスにない$fを返す
        return static::$f;
    }
}

class Fuga extends Hoge {
    protected static $f = "fooooo";

    public static function f() {
        return static::h();
    }
}

print_r( Fuga::f() ); //=> fooooo

抽象クラスのクラスメソッドは呼べる

<?php
class Hoge {
    public static function h() {
        return "hooooooooooo!";
    }
}

print_r( Hoge::h() ); //=> hooooooooooo!

リファレンス渡し

<?php
class Hoge {
    private $h;

    // リファレンス
    public function __construct(&$h) {
        $this->h =& $h;
    }

    // リファレンス...
    public function &ref_h() {
        return $this->h;
    }

    // リファレンス......
    public function fff() {
        $h =& $this->ref_h();
        $h["str"] = "changed";
    }
}

$abc = array("str" => "hoooo!");

$h = new Hoge($abc);
$h->fff();

print_r($abc); //=> Array( [str] => changed )
  • 渡したいときには、コールする方ではなくて、定義する方に&をつける
  • 返したいときには、関数名に&をつける
  • 左辺で受け取るときは=の右に&をつける

インスタンスメソッド内でのインスタンスメソッドの呼び出し(複数

<?php
class Hoge {
    public function h1() {
        echo "h1\n";
    }

    public function h2() {
        $this->h1(); //=> h1
        self::h1();  //=> h1
        h1(); //=> Fatal error: Call to undefined function h1()
    }
}

$hoge = new Hoge();
$hoge->h2();
  • $thisかselfを省略しては呼べない
  • selfあれば$this要らないのかな?

ジェネレータ(v5.5〜)

<?php

function hoge() {
    foreach (range(1, 5) as $i) {
        yield $i;
    }
}

foreach (hoge() as $i) {
    echo "$i\n";
}
//=> 1
//=> 2
//=> 3
//=> 4
//=> 5

インスタンスからクラスメソッドを呼ぶ

<?php
class Hoge {
    public static function h() {
        return "h";
    }
}

$hoge = new Hoge();
print_r( $hoge::h() ); //=> h
  • ::演算子を使うと、そのクラスのプロパティなりメソッドなりにアクセスできる

文字列扱いされたときは__toStringが呼ばれる

<?php
class Hoge {
    public function __toString() {
        return "hoge object";
    }
}

$hoge = new Hoge();
print_r( "$hoge" ); //=> hoge object

メソッドシグネチャ

<?php
class Hoge {
    public function h() {
        return "h";
    }
}

class Fuga extends Hoge {
    public function h($w) {
       return parent::h().$w;
    }
}

$fuga = new Fuga();
print_r( $fuga->h("f") ); //=> hf

// E_STRICT レベルのエラー
// Strict standards: Declaration of Fuga::h() should be compatible with Hoge::www()
  • 引数の数と型を合わせないといけないようだ

arrayとforeachの&

<?php
$a = array(1, 2, 3);
$b = array(4, 5, 6);

foreach (array($a, &$b) as &$c) {
    foreach ($c as &$d) {
        $d *= 100;
    }
}

print_r($a); //=> Array ( [0] => 1 [1] => 2 [2] => 3 )

print_r($b); //=> Array ( [0] => 400 [1] => 500 [2] => 600 )
  • arrayの中でも&をつけることができる

無名関数にselfを入れて返却(v5.4〜)

<?php
class Hoge {
    protected static function h($proc) {
        return $proc();
    }

    protected static function aaa() {
        return "aaaaaaa";
    }
}

class Fuga extends Hoge {
    public static function f() {
        $proc = function(){ return self::aaa(); };
        return static::h($proc);
    }
}

print_r( Fuga::f() ); //=> "aaaaaaa"

無名関数に$thisを入れて返却(v5.4〜)

<?php
class Hoge {
    protected function h($proc) {
        return $proc();
    }

    protected function aaa() {
        return "aaaaaaa";
    }
}

class Fuga extends Hoge {
    public function f() {
        $proc = function(){ return $this->aaa(); };
        return $this->h($proc);
    }
}

$fuga = new Fuga();
print_r( $fuga->f() );  //=> "aaaaaaa"

インスタンスが親のstaticメソッドを呼び出し

<?php
class Hoge {
    public static function h($w) {
        print_r( $w );
    }
}

class Fuga extends Hoge {
    public function f() {
        parent::h('fooooo');
    }
}

$fuga = new Fuga();
$fuga->f(); // fooooo
  • parent::を使う

インスタンスメソッド内のstaticは各インスタンス間で共通

<?php
class Hoge {
    public function h() {
        static $h = 100;
        $h++;
        return $h;
    }
}

$hoge1 = new Hoge();
print_r( $hoge1->h() ); //=> 101

$hoge2 = new Hoge();
print_r( $hoge2->h() ); //=> 102

メソッド内のstaticに式は書けない

<?php
class Hoge {
    public function h() {
        static $h = 100 + 100;
        return $h;
    }
}

$hoge = new Hoge();
print_r( $hoge->h() );
// Parse error: syntax error, unexpected '+', expecting ',' or ';' in /tmp/i_AoXbiC__ on line 4

関数名を引数にとるときにstaticメソッドを渡したい

<?php
class Hoge {
    public static function h() {
        $aaa = array(
            array('id' => 45),
            array('id' => 83),
            array('id' => 28),
        );
        usort($aaa, array('Hoge', 'mysort')); // usortの第二引数をarrayにする
        return $aaa;
    }

    public static function mysort($a, $b) {
        return ($a['id'] < $b['id']) ? -1 : 1;
    }
}

print_r( Hoge::h() );
  • クラス名を文字列にしてarrayで渡す

__getはprivateメンバ変数関係なく常に呼ばれる

<?php
class Hoge {
  public function __get($name) {
    return $name;
  }
}

$hoge = new Hoge();
print_r( $hoge->foooo ); //=> foooo

メンバ変数やstatic変数に定数を使う

<?php
class Hoge {
    const HHH = "hhh";

    private static $h = self::HHH;
    private $w = self::HHH;

    public static function h() {
        return static::$h;
    }

    public function w() {
        return $this->w;
    }
}

print_r( Hoge::h() ); //=> hhh

$hoge = new Hoge();
print_r( $hoge->w() ); //=> hhh

arrayの返り値を直接取り出せない(〜v5.3)

<?php
function h() {
    return array('str' => 'h');
}

print_r( h()['str'] );
//=> PHP Parse error

print_r( array('str' => 'h')['str'] );
//=> PHP Parse error

メソッドチェインはできる

<?php
class Hoge {
    public function h() {
        return "hhh";
    }
}

class Fuga {
    public function f() {
        $hoge = new Hoge();
        return $hoge;
    }
}

$fuga = new Fuga();
print_r( $fuga->f()->h() ); //=> hhh

||や&&はbooleanを返す

<?php
function h() {
    return null;
}

function f() {
    return "fff";
}

$a = h() || f();

print_r( $a ); //=> 1
<?php
function s() {
    return "sss";
}

function d() {
    return "ddd";
}

$b = s() && d();

print_r( $b ); //=> 1
  • andやorでも同様
  • これはつらい

rangeはマイナスにも動く

<?php
foreach (range(10, 5) as $i) {
  echo "$i\n";
}

//=> 10
//=> 9
//=> 8
//=> 7
//=> 6
//=> 5