アヒルは「鳴き声」、てんとう虫は「mu-mu」、「Runn Me!」と言います-次のPHPフレームワーク*が教えてくれます。 パート1

「ああ、いや!」読者は、さまざまなミニマイクロスリムフレームワークとQueryBuilderにうんざりしていると叫ぶでしょう。



次のPHPフレームワークほど退屈なものはありません。 それは「根本的に新しい」CMS か、新しいデートですか。







では、なぜ私は最高のアプリケーションに値する頑固さを持って歩き、不快な落とし穴に沿って歩き、 娯楽のために観客に私の仲間のコートを展示するのですか? 批評家の怒り、津波がこの投稿にどれほど強力になり、それをHabrの最下部に埋めるのかを事前に知っていますか?



知りません コロンブスは、スペインの居心地の良い海岸を航行する理由を一度も知りませんでした。 彼はインドへの道を見つけたいと思っていましたか? もちろんそうです。 しかし、彼は確かに知りませんでした-彼は泳ぐでしょうか?



どうやら、私が13年間自分自身を分類してきたPHPプログラマーには、同じ内部ニーズがあります。コードを公開し、目を閉じて、同僚の反応を待っています。



カットの下であなたを待っていますか?





さて、そしてもちろん、フレームワークの松葉杖駆動に関する次の自転車の発明の話*!



*一般的に言って、これはまだフレームワークではありませんが、単なるライブラリのセットであり、少し後にフレームワークになります







ちょっとした歴史や、「別のフレームワークを書く」というアイデアはどこから来たのですか?



はい、実際、どこからともなく。 彼女はいつもそうでした。



プログラミングのキャリアの中で参加したさまざまな興味深いプロジェクトは、標準的なタスクの標準的なソリューションを個人の貯金箱に入れました-私と同じように、通常のプログラマーのように、関数、クラス、ライブラリのライブラリが蓄積されました。



約6年前、私がその時に働いていた会社の経営陣は、独自のフレームワークを開発するというタスクを設定しました。 軽量のMVCフレームワークを作成し、最も必要なものだけを使用して、サブジェクト領域の特定のライブラリを追加し(信じてください-非常に具体的です!)、何らかの汎用ソリューションをまとめます。 解決策は判明しましたが、問題は特定されましたが、サブジェクト領域の特異性により、それが広まることができませんでした-コードは公開されず、インストールはクライアントのサイトで販売されました。 なんて残念。 いくつかのことは本当に時代遅れでした:原始的な、しかしかなり似ている作曲家ですが、チームと私は完全に独立しており、実際の安定した公の作曲家より少し前に登場したと言って十分です:)



この経験のおかげで、当時PHPエコシステムに存在していたほとんどすべてのフレームワークを研究することができました。 その過程で、別のイベントが発生しました。別の「量から品質への移行」-私はプログラミングを教え始めました。 最初は有名なオンラインスクールの1つで、彼は自分のサービスの開発に集中しました。 彼は、教授法、教材、そしてもちろん学生とともに「成長」し始めました。 このパーティーでは、「トレーニングフレームワーク」というアイデアが生まれました。これは、初心者が理解しやすいように意図的に簡素化されましたが、同時に現代の標準とトレンドに従って単純なWebアプリケーションを開発できるようになりました。



3年前、この「教育フレームワーク」のアイデアの実現として、小さな「MVCフレームワーク」が「T4」という名前で誕生しました*。 名前は特別なものではなく、「Technological layout、version 4」の略です。 前の3つのバージョンが失敗したことは明らかだと思います。4回目の試行で、当時の生徒たちと一緒に、本当に面白いものを作成することができました。



*後に、第三帝国で末期の人々を殺菌し殺すためのプログラムが呼ばれたことを知りました...もちろん、すぐに名前を変えるという疑問が生じました



T4の開発と成長は成功し、知られるようになりました。「狭い円で」(非常に狭い)と言われ、かなり大きなプロジェクトがいくつか行われましたが、この決定に対する内部の不満も高まりました。



今年の初めに、私はようやく成熟して蓄積されたコードを再フォーマットしました。 T4を積極的に使用している志を同じくする人々のグループとともに、新しいフレームワークを構築するためのいくつかの基本原則を採用しました。



  1. 各ライブラリを個別に接続して使用できるように、疎結合ライブラリのセットにします。
  2. 可能な限り健康的なミニマリズムを維持しようとする
  3. Webおよびコンソールアプリケーションのフレームワーク自体もライブラリの1つであるため、モノリシック性が回避されます。
  4. 車輪を再発明しないようにし、可能な限りこれらのアプローチとT4ですでに確立されているコードを保持します。
  5. 旧バージョンのPHPのサポートは拒否し、最新バージョンのコードを作成します。
  6. コードをできる限り柔軟にするよう努めています。 可能であれば、クラスと継承の代わりに、インターフェイス、特性、およびコード構成を使用して、フレームワークのユーザーがコンポーネントの参照実装を独自のものに置き換える機会を残します。
  7. コードをテストでカバーし、100%のカバレッジを達成します。


そのため、プロジェクトは最初に「Running.FM」と呼ばれ、その後「Runn Me!」に名前が変更されました



今日私が代表しているのは彼です。



ちなみに、「runn」という単語は人為的に作成されています。一方では、すべての人が理解できるようにし、他方では「run」との関連付けを行い、辞書の単語と一致しないようにします。 私は一般的に「実行」の組み合わせが好きです:私はまだ一度にRunCMSに参加することができました:)



現時点では、Runn Me!プロジェクトは現在進行中です-一部のライブラリは既に実稼働で使用できます。一部は古いプロジェクトからの転送とリファクタリングのプロセスで、一部はまだ転送が開始されていません。



最初はコアでした



Runn Me!プロジェクトの各ライブラリに関する記事を1つの投稿に収めることは不可能です。プロジェクトが多数あります。それぞれについて詳しく説明したいと思います。また、これはすべてが文字通り毎日より良くなるプロジェクトです。



そのため、プロジェクトのストーリーをいくつかの投稿に分割することにしました。 今日は、「コア」と呼ばれるベースライブラリについて説明します。





アレイ? オブジェクト? それとも一緒に?



配列内の要素のように、その場で作成および削除できる任意のプロパティで構成されるオブジェクトという肥沃なアイデアは、すべてのPHPプログラマーの頭に浮かびます。 そして、毎秒1つがこのアイデアを実装しています。 私も例外ではありませんでした。私と私のチーム:Runn \ Coreライブラリの紹介私は、ObjectAsArrayの概念についての話から始めたいと思います。



一度行う:オブジェクトを配列にキャストできるインターフェースを定義し、その逆も同様です:このインターフェースのいくつかの便利なメソッドを忘れずに配列をオブジェクトに変換します(オブジェクトを外部データとマージし、配列に再帰的にキャストするためのマージ())



github.com/RunnMe/Core/blob/master/src/Core/ArrayCastingInterface.php

namespace Runn\Core;

interface ArrayCastingInterface
{
    public function fromArray(iterable $data);
    public function merge(iterable $data);
    public function toArray(): array;
    public function toArrayRecursive(): array;
}

      
      





: , -- , : , , , , «-».



github.com/RunnMe/Core/blob/master/src/Core/ObjectAsArrayInterface.php

namespace Runn\Core;

interface ObjectAsArrayInterface
  extends \ArrayAccess, \Countable, \Iterator, ArrayCastingInterface, HasInnerCastingInterface, \Serializable, \JsonSerializable
{
  ...
}

      
      





: , . . github.com/RunnMe/Core/blob/master/src/Core/ObjectAsArrayTrait.php



«--». ObjectAsArrayInterface ObjectAsArrayTrait :



class someObjAsArray implements \Runn\Core\ObjectAsArrayInterface 
{
  use \Runn\Core\ObjectAsArrayTrait;
}

$obj = (new someObjAsArray)->fromArray([1 => 'foo', 2 => 'bar']);
$obj[] = 'baz';
$obj[4] = 'bla';

assert(4 === count($obj));
assert([1 => 'foo', 2 => 'bar', 3 => 'baz', 4 => 'bla'] === $obj->values());

foreach ($obj as $key => $val) {
  // ...
}

assert('{"1":"foo","2":"bar","3":"baz","4":"bla"}' === json_encode($obj));

      
      





ObjectAsArrayTrait « -» -, :



class customObjAsArray implements \Runn\Core\ObjectAsArrayInterface 
{

  use \Runn\Core\ObjectAsArrayTrait;

  protected function getFoo() 
  {
    return 42;
  }

  protected function setBar($value)
  {
    echo $value;
  }

}

$obj = new customObjAsArray;
assert(42 === $obj['foo']);

$obj['bar'] = 13; //  13,   

      
      





: null is set!



, -, null, .



, - . , , , ORM:



class someObjAsArray implements \Runn\Core\ObjectAsArrayInterface 
{
  use \Runn\Core\ObjectAsArrayTrait;
}

$obj = new someObjAsArray;
assert(false === isset($obj['foo']));
assert(null === $obj['foo']);

$obj['foo'] = null;
assert(true === isset($obj['foo']));
assert(null === $obj['foo']);

      
      





?



! , — . \Runn\Core\ObjectAsArrayInterface , « »: Collection Std.





Runn Me! — -, :



namespace Runn\Core;

interface CollectionInterface
    extends ObjectAsArrayInterface
{
    public function add($value);
    public function prepend($value);
    public function append($value);
    public function slice(int $offset, int $length = null);
    public function first();
    public function last();
    public function existsElementByAttributes(iterable $attributes);
    public function findAllByAttributes(iterable $attributes);
    public function findByAttributes(iterable $attributes);
    public function asort();
    public function ksort();
    public function uasort(callable $callback);
    public function uksort(callable $callback);
    public function natsort();
    public function natcasesort();
    public function sort(callable $callback);
    public function reverse();
    public function map(callable $callback);
    public function filter(callable $callback);
    public function reduce($start, callable $callback);
    public function collect($what);
    public function group($by);
    public function __call(string $method, array $params = []);
}

      
      







, CollectionTrait, ( ) \Runn\Core\Collection, .



:



$collection = new Collection([1 => 'foo', 2 => 'bar', 3 => 'baz']);
$collection->prepend('bla');

$collection
  ->reverse()
  ->map(function ($x) { 
    return $x . '!'; 
  })
  ->group(function ($x) {
    return substr($x, 0, 1);
  });

/*
 - 
[
  'b' => new Collection([0 => 'baz!', 1 => 'bar!', 2 => 'bla!']),
  'f' => new Collection([0 => 'foo!'),
),
]
*/

      
      





?



  1. , .
  2. .
  3. — .




«» Runn\Core , , . .



:



class UsersCollection extends \Runn\Core\TypedCollection 
{
  public static function getType()
  {
    return User::class; //       , 
  }  
}

$collection = new UsersCollection;

$collection[] = 42; // Exception: Typed collection type mismatch
$collection->prepend(new stdClass); // Exception: Typed collection type mismatch

$collection->append(new User); // Success!

      
      





Std



«» , - , « ». :



: «».



namespace Runn\Core;

interface StdGetSetInterface
{
    public function __isset($key);
    public function __unset($key);
    public function __get($key);
    public function __set($key, $val);
}

      
      





: (. github.com/RunnMe/Core/blob/master/src/Core/StdGetSetTrait.php )



: «» , StdGetSetInterface . github.com/RunnMe/Core/blob/master/src/Core/Std.php



, . :



$obj = new Std(['foo' => 42, 'bar' => 'bla-bla', 'baz' => [1, 2, 3]]);
assert(3 === count($obj));

assert(42 === $obj->foo);
assert(42 === $obj['foo']);

assert(Std::class == get_class($obj->baz));
assert([1, 2, 3] === $obj->baz->values());

// , ,      :
$obj = new Std;
$obj->foo->bar = 42;
assert(Std::class === get_class($obj->foo));
assert(42 === $obj->foo->bar);

      
      





, «» Std chaining-, , , . : , .. , .



?



! :





. , ! , , ! :)







P.S. , - . «». .



P.P.S. .



©



() Mart Virkus 2016




All Articles