Php: получить подсказку типа переменной с использованием отражения
class Expense {
/**
* @var int
*/
private $id;
}
Я хотел бы получить тип подсказки переменной в моем классе, используя отражение, потому что значение по умолчанию равно null.
Ответы
Ответ 1
Try:
<?php
class Expense {
/**
* @var int
*/
private $id;
}
$refClass = new ReflectionClass('Expense');
foreach ($refClass->getProperties() as $refProperty) {
if (preg_match('/@var\s+([^\s]+)/', $refProperty->getDocComment(), $matches)) {
list(, $type) = $matches;
var_dump($type);
}
}
Выход
string(3) "int"
Ответ 2
Получить полный Docblock:
$reflection = new ReflectionProperty('Expense', 'id');
$doc = $reflection->getDocComment();
Ответ 3
Немного предупреждения - PHP-ускорители и некоторые библиотеки (т.е. symfony core) не просто компилируют комментарии, нередко на втором запуске.
Ответ 4
Если комментарии PHPDoc оказываются отсутствующими или ненадежными, вы можете напечатать подсказку для всех свойств класса, если они имеют соответствующий метод получения.
public function getClassPropertiesType(string $className): array {
$reflectionClass = new \ReflectionClass($className);
$reflectionProperties = $reflectionClass->getProperties();
$properties = [];
foreach ($reflectionProperties as $reflectionProperty) {
$properties[] = $reflectionProperty->getName();
}
$methods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);
$results = [];
foreach ($properties as $property) {
foreach ($methods as $method) {
// get only methods that have 0 parameter and start with 'get'
if ($method->getNumberOfParameters() === 0 &&
strpos($method->getName(),'get') !== false &&
stripos($method->getName(), $property) !== false) {
$results[$property] = (string)$method->getReturnType();
}
}
}
return $results;
}
По логике, для каждого свойства класса должен быть только один метод получения.
Если я дам дамп свойств некоторого класса:
0 => "id"
1 => "email"
2 => "password"
3 => "firstName"
4 => "lastName"
5 => "gender"
6 => "position"
7 => "isActive"
9 => "dateEmployedFrom"
10 => "dateEmployedTo"
11 => "dateOfBirth"
12 => "ssn"
13 => "mobilePhone"
14 => "homePhone"
15 => "address"
16 => "zipCode"
17 => "city"
18 => "country"
Вот что вы получаете:
"id" => "int"
"email" => "string"
"password" => "string"
"firstName" => "string"
"lastName" => "string"
"gender" => "bool"
"position" => "string"
"isActive" => "bool"
"dateEmployedFrom" => "DateTimeInterface"
"dateEmployedTo" => "DateTimeInterface"
"dateOfBirth" => "DateTimeInterface"
"ssn" => "string"
"mobilePhone" => "string"
"homePhone" => "string"
"address" => "string"
"zipCode" => "string"
"city" => "string"
"country" => "string"
Ограничения + обходной путь
Если у свойства нет какого-либо метода получения, вы можете начать поиск методов установки (или методов, которые начинаются с 'add', 'is', 'remove'), при условии, что аргументы метода имеют подсказку типа. Вы также можете включить частную собственность в свой поиск $methods = $reflectionClass->getMethods(); // no filter
Я предлагаю расширить, как это, прежде чем вернуться:
$missingProperties = array_diff_key(array_flip($properties), $results);
if (!empty($missingProperties)) { // some properties are missing
foreach ($missingProperties as $missingProperty => $val) {
// get only methods that have 1 parameter and start with 'set'
if ($method->getNumberOfParameters() === 1 && strpos($method->getName(), 'set') !== false) {
$parameters = $method->getParameters();
// if not already in results, and parameter is required
// and is a class property
if(!array_key_exists($parameters[0]->getName(), $results) &&
!$parameters[0]->isOptional() &&
in_array($parameters[0]->getName(), $properties, true)) {
$string = $parameters[0]->__toString();
$string = substr($string, strlen('Parameter #0 [ <required> '));
$pos = strpos($string, ' '); // get first space after type
$string = substr($string, 0, $pos); // get type
$results[$parameters[0]->getName()] = $string;
}
}
}
}
Конечно, это не на 100% пуленепробиваемый, но, надеюсь, это поможет. :-)
Последнее: PHP 7.4 представляет ReflectionParameter :: getType
Таким образом, вы можете отказаться от приведенной выше операции со строками и просто написать:
$type = $parameters[0]->getType();
$results[$parameters[0]->getName()] = $type->__toString();