Skip to content

make:entity: public properties instead of private + accessorsΒ #1764

@alcaeus

Description

@alcaeus

I'm creating this issue to trigger a discussion around how we want the maker bundle to generate entities. Until now, entities always store private properties and add accessors to manipulate the values. While this provides a fluent interface for setters, it's also somewhat of an anti-pattern, especially in modern PHP. There were multiple reasons why one would not want to expose properties in classes, instead using getters and various modifier methods:

  • accessors needing to contain logic, e.g. validation
  • asymmetric access (e.g. for the identifier which does not have a setter)
  • more expressive methods, e.g. addSomething and removeSomething with typed parameters instead of working through the generic collection
  • future-proofing, i.e. "let me add setters and getters in case I need to add logic later"

While all this may have been a best practice in the past, there are multiple reasons why we no longer need to do this:

  • With property hooks, we can transparently add logic to property access after the fact, negating the need for dedicated setters and getters
  • Asymmetric visibility is supported on the property level, negating the need for getters for unmodifiable properties
  • Refactoring tools can be used instead of future-proofing in cases where property access needs to be changed to calling a method

My suggestion would be to change the maker to no longer generate setters and getters for properties, but since this is quite a big change, I wanted to get some input on this first. There are also a few special cases that might need discussing. I've prototyped some changes locally, and here's what I found so far: we can relatively easily remove accessors for most properties and make them public. This doesn't necessarily create a BC break but we may want to make the behaviour opt-in. We would have to bump the PHP requirement to PHP 8.4, as the identifier would need to have a private(set) modifier to replicate current behaviour. Where it gets tricky are the various relationships. The current methods handle things like updating the inverse side of a relationship (i.e. calling setOwner on $child when $owner->addChild($child) is called). This can't be done through property hooks, but would have to be handled in the corresponding collection instance. The problem is that this instance may not yet be aware of this requirement, as only a PersistentCollection knows about mappings and inverse sides, while the ArrayCollection created when the entity instance is created outside of Doctrine has no idea of mappings or anything. Last but not least, we would still want a private(set) modifier for collection properties by default to ensure that the collection instance itself can't be replaced, as that may trigger really unwanted behaviour.

I would create a pull request for changing "normal" properties (i.e. identifier and anything that isn't an association) to public and omitting setters and getters, but would like to know if we should make this the new default behaviour or whether we should add some kind of BC layer. For associations, I'm appreciative of any input people have with how these should behave by default.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions