Skip to content

Conversation

supun-io
Copy link

@supun-io supun-io commented Mar 2, 2025

Problem: an easy way to access the names of the properties of an object or a class.

Solution: property-of<MyObject> utility type

Example:

class CreateSubscriberDto
{

    public string $email;
    public int $listId;

    /**
     * @param property-of<self> $property
     * @return bool
     */
    public function hasProperty(string $property): bool
    {
        dumpType($property); // 'email'|'listId'

        // ...
    }

}

$dto = new CreateSubscriberDto();
$dto->hasProperty('email'); // no error
$dto->hasProperty('listId'); // no error
$dto->hasProperty('notExisting'); // shows static error

TODO:

  • Implement a template-supported version in PHPStan\Type\Generic

Notes:

Most of the code was taken from KeyOfType.

If the idea is accepted, I will work on the implementation of the template-supported version.

@herndlm
Copy link
Contributor

herndlm commented Mar 3, 2025

jfyi this is also related to what I was asking recently in phpstan/phpstan#12240. consider this a neutral comment, I don't mean that adding it here is good or bad.

this is a highly specific thing potentially, but having a utility for this in phpstan itself might make sense. in my case I needed something even more special for our app in the end anyway, because I also had to check if the property has a default value assigned or not. so I ended up with a properties-without-default-value-of<> utility to make some risky behaviour we have more (type-)safe 😊

@ondrejmirtes
Copy link
Member

I've rejected this in the past because different users might have different needs. There are many decisions about object properties you need to make:

  • Only native properties, or with magic properties (@method, __get etc.) as well?
  • Only public properties, or private+protected as well?
  • Only instance properties, or static properties too?
  • What about universalObjectCratesClasses? Does this return a general array<string, mixed> for them or not?

Because of these uncertainties, every project can implement their own version using https://phpstan.org/developing-extensions/custom-phpdoc-types.

@supun-io
Copy link
Author

supun-io commented Mar 3, 2025

yes, I understand that there are variations of the problem, but still, this is a very common case in PHP, especially when using DTOs.

Would it make sense to have a second parameter that accepts a ReflectionProperty constant to cover all the cases including static virtual, set, final, etc.

// all
property-of<self>

// static only
property-of<self, ReflectionProperty::IS_STATIC>

// protected or private
property-of<self, ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE>

// static and public
property-of<self, ReflectionProperty::IS_STATIC & ReflectionProperty::IS_PUBLIC>

We can simply pass the second parameter to getProperties of the class reflection. This is assuming PHPDoc can parse bitwise operators correctly (which I am not sure)

This solution solves:

  • Only native properties,
  • Only public properties, or private+protected as well?
  • Only instance properties, or static properties too?

But not

  • magic properties (@method, __get etc.) as well?
    I think we could somehow support @method, but __get is going to be difficult

  • What about universalObjectCratesClasses? Does this return a general array<string, mixed> for them or not?
    Just mixed for them?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants