<?php

class YobaORM {
    /**
     * @param   string  $type_name
     * @return  object[]
     */
    static function all($type_name) {
        echo 'YobaORM::all('.$type_name.')'.PHP_EOL;
        return array_map(
            function($id) use($type_name) {
                return new $type_name(array('id'=>$id));
            },
            range(1, 5)
        );
    }

    /**
     * @param   string  $type_name
     * @param   int     $id
     * @return  object
     */
    static function find($type_name, $id) {
        echo 'YobaORM::find('.$type_name.','.$id.')'.PHP_EOL;
        return new $type_name(array('id' => $id));
    }
}

abstract class AbstractYobaEntity {
    /**
     * @return  static[]
     */
    static function all() {
        return YobaORM::all(get_called_class());
    }

    /**
     * @param   int $id
     * @return  static
     */
    static function find($id) {
        return YobaORM::find(get_called_class(), $id);
    }
}

class SomeYobaEntity extends AbstractYobaEntity {
    /**
     * @var int
     */
    protected $id;
    /**
     * @var string
     */
    protected $lal;

    function __construct($ary = array()) {
        $this->id = isset($ary['id']) ? $ary['id'] : null;
        $this->lal = isset($ary['lal']) ? $ary['lal'] : '{{'.rand().'}}';
    }

    /**
     * @return  int
     */
    function getId() {
        return $this->id;
    }

    /**
     * @return  string
     */
    function getLal() {
        return $this->lal;
    }
}

$y = SomeYobaEntity::find(3);
echo $y->getId().','.$y->getLal().PHP_EOL;

$all_that_yobas = SomeYobaEntity::all();
foreach ($all_that_yobas as $yo) {
    echo $yo->getId().','.$yo->getLal().PHP_EOL;
}
