読めるけど書けない

April 9, 2013,
tags: php


このエントリーをはてなブックマークに追加

読めるけど書けない修飾子としてPHPには「niigata新潟アクセス修飾子」という@supper_rtiさんが作ってくれたパッチが存在します。
ネタと言えばネタだけど、とても素敵だし、本家にも実装してほしい機能の一つだったりもしますw
でもパッチ当てるのは実際面倒だし・・・そもそもそういう事が出来ない環境だけど、niigataアクセス修飾子が欲しくなるときは多々あるかと思います。

__get()使えば普通に実装できるって話も聞いてたので、実際に実装してみました。
速度的にはあれだけど、まあ遊びとして使う分にはありかと思いますw

<?php
abstract class Lemon {
  protected $__isNigata2Properties;
  protected $__isFinalProperties;


  public function __construct() {

    $this->__isNigata2Properties = array();
    $this->__isFinalProperties = array();
    $refectionClass = new ReflectionClass($this);
    foreach ($refectionClass->getProperties() as $property) {
      if ($property->getDocComment() === false) {
        continue;
      }
      if ($property->isPublic()) {
        continue;
      }

      foreach (explode("\n",$property->getDocComment()) as $value) {
        $value = str_replace(array("\t", "*", "\n", " "), "", $value);
        if ($this->__isNiigataAccess($value)) {
          $this->__isNigata2Properties[$property->getName()] = true;
          $this->__isFinalProperties[$property->getName()] = $this->__isFinalAccess($value);
          break;
        }
      }

    }
  }

  /**
   * GETマジックメソッド
   * @param string $name
   * @return string
   */
  public function __get($name) {
    if (isset($this->__isNigata2Properties[$name])) {
      $reflection = new ReflectionProperty($this,$name);
      $reflection->setAccessible(true);
      if ($this->__isFinalProperties[$name]) {
        $refectionClass = new ReflectionClass($this);
        $defaultProperties = $refectionClass->getDefaultProperties();
        return $defaultProperties[$name];
      } else {
        return $reflection->getValue($this);
      }
    } else {
      return parent::__get($name);
    }
  }

  /**
   * 檸檬かどうかのチェックを行う
   * @param string $value
   * @return boolean
   */
  protected function __isNiigataAccess($value) {
    return (strpos($value,"@access") !== false && strpos($value,"lemon"));
  }

  protected function __isFinalAccess($value) {
    return (strpos($value,"@access") !== false && strpos($value,"final"));
  }

}


// 以下テスト
// 変数のプロパティに対して「@access」のあとに「lemon」、「檸檬」、「れもん」とか
// つければプライベートな変数にアクセスできる
class Hoge extends Lemon {

  /**
   * @access lemon
   */
  private $hoge = "れもん";

  /**
   * @access final lemon
   */
  private $hoge2 = "イエロー";

  public function change() {
    $this->hoge = "レモン汁";
  }

  public function change2() {
    $this->hoge2 = "ぶるー";
  }

  public function check() {
    var_dump($this->hoge2);
  }

}

$hoge = new Hoge();
var_dump($hoge->hoge);
$hoge->change();
var_dump($hoge->hoge);
var_dump("----");
var_dump($hoge->hoge2);
$hoge->change2();
var_dump($hoge->hoge2);

comments powered by Disqus