kphp
kphp copied to clipboard
@kphp-template and instance_cast($object, T:class)
Цель изменения:
если получаем шаблонный тип T , то все его использования должны подставиться на тип реализации шаблона. Это ускорит исполнение работы с коллекциями целевого типа, а не интерфейсного при распаковке из внешних источников при котором надо проверять соответствие типу в каждом применении или повторно создавать коллекцию.
пример:
/**
* @param $proto
* @return object
* @kphp-template T $proto
* @kphp-return T
*/
public function get(object $proto) : T
{
return instance_cast($this->object, T::class);
}
$instanceA = $holder->get(new A);
$instanceB = $holder->get(new B)
ожидание: создана функция по шаблону, если получаем шаблонный тип T , то все его использования должны подставиться на тип реализации шаблона
class_instance<C$A> f$Holder$$get$A(class_instance<C$Holder> const &v$this, class_instance<C$A> const &v$proto) noexcept {
//62: {
//63: return instance_cast($this->object, T::class);
return f$instance_cast< class_instance<C$A> >(v$this->$object, v$const_string$a_key);
}
сейчас по факту: 1 . результат не раскрылся 2. подстановка для instance_cast
не раскрылась
//source = [testTemplate.php]
//61: public function get(object $proto) : T
class_instance<C$T> f$Holder$$get$A(class_instance<C$Holder> const &v$this, class_instance<C$A> const &v$proto) noexcept {
//62: {
//63: return instance_cast($this->object, T::class);
return f$instance_cast< class_instance<C$T> >(v$this->$object, v$const_string$usf7aa15be8a7d743e);
}
Практическое применение:
/**
* @param Holder $holder
* @param object $class
* @param $docs
* @return array
* @kphp-template T $class
* @kphp-return T[]
*/
function createArray(Holder $holder, $class): array
{
$docs = [new T]; //try to create T[]
for ($i = 0; $i < 10; ++$i) {
$docs[] = instance_cast(clone $holder->object, T::class);
}
return $docs;
}
$arrayA = createArray($holder, new A); // expect result A[]
$arrayB = createArray($holder, new B); // expect result A[]
полный код теста
class T{}
interface I{ }
class A implements I { function methodA(){ echo "A"; } }
class B implements I { function methodB(){ echo "B"; } }
class Holder
{
public I $object;
/**
* Holder constructor.
* @param I $object
* @kphp-template I $object
*/
public function __construct( $object)
{
$this->object = $object;
}
/**
* @param object $object
* @kphp-template $object
* @return Holder
*/
public static function create(object $object)
{
return new Holder($object);
}
/**
* @param $proto
* @return object
* @kphp-template T $proto
* @kphp-return T
*/
public function get(object $proto)
{
return instance_cast($this->object, T::class);
}
}
$holderA = Holder::create(new A());
$holderB = Holder::create(new B());
/** @var A $varA */
$varA = $holderA->get(new A);
$varA->methodA();
/** @var B $varB */
$varB = $holderB->get(new B);
$varB->methodB();
/**
* @param Holder $holder
* @param object $class
* @param $docs
* @return array
* @kphp-template T $class
* @kphp-return T[]
*/
function fillWithCast(Holder $holder, $class): array
{
$docs = [$class];
for ($i = 0; $i < 10; ++$i) {
$docs[] = instance_cast(clone $holder->object, T::class);
}
return $docs;
}
/** @var A[] $arrayA */
$arrayA = [];
$arrayA = fillWithCast(new Holder(new A), new A);
$arrayA[0]->methodA();
/** @var B[] $arrayB */
$arrayB = [];
$arrayB = fillWithCast(new Holder(new B), new B);
$arrayB[0]->methodB();