class Expense {
/**
* @var int
*/
private $id;
}
Я хотел бы получить тип подсказки переменной в моем классе, используя отражение, потому что значение по умолчанию равно null.
class Expense {
/**
* @var int
*/
private $id;
}
Я хотел бы получить тип подсказки переменной в моем классе, используя отражение, потому что значение по умолчанию равно null.
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"
Получить полный Docblock:
$reflection = new ReflectionProperty('Expense', 'id');
$doc = $reflection->getDocComment();
Немного предупреждения - PHP-ускорители и некоторые библиотеки (т.е. symfony core) не просто компилируют комментарии, нередко на втором запуске.
Если комментарии 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();