Hi,

As the initiator of this discussion, I would like to summarize it well, but
I need this a little more time.
Discussion was lively and I would like all the arguments to be included in
the summary.

It seems to me that I would need this help, and I am eager to progress and
evolution of language PHP.
Do any of you would be willing to support me mentally to create this
summary?

regards,
--
Michał Brzuchalski

2016-08-15 21:00 GMT+02:00 Fleshgrinder <p...@fleshgrinder.com>:

> On 8/15/2016 12:11 AM, Stanislav Malyshev wrote:
> > Hi!
> >
> >> - PHP 7 has private classes through anonymous/inner classes.
> >
> > It's not exactly the same, and I suspect the same is true for Ruby. It's
> > true that anonymous classes can not be instantiated by other code. But
> > that is not what we were discussing here. This particular effect is
> > somewhat similar, the purpose of the feature is different.
> >
>
> It is part of what we are discussing.
>
> On 8/15/2016 12:11 AM, Stanislav Malyshev wrote:
> > Of course, some languages have them. Others don't. The point is saying
> > "it's not OO unless it implements $favorite_feature_of_mine" is not very
> > meaningful, at least at this point.
> >
>
> I never said that I agree with that particular comment since you are
> completely right that this is not true. Visibility modifiers do not
> require OO and OO does not require visibility modifiers.
>
> On 8/15/2016 12:11 AM, Stanislav Malyshev wrote:
> >> abstract class Data {
> >>   protected $id;
> >>   protected $name;
> >>   protected function __construct() {}
> >>   protected function __clone() {}
> >> }
> >>
> >> final class Entity extends Data {
> >>   public function getId() {
> >>     return $this->id;
> >>   }
> >>   public function getName() {
> >>     return $this->name;
> >>   }
> >> }
> >>
> >> final class Builder extends Data {
> >>   private $entity;
> >>   public function build() {
> >>     return clone $this->entity;
> >>   }
> >>   public function setId($id) {
> >>     $this->entity->id = $id;
> >>   }
> >>   public function setName($name) {
> >>     $this->entity->name = $name;
> >>   }
> >> }
> >>
> >> ?>
> >
> > I'm afraid I don't understand this code. Why both entity and builder are
> > Data? It looks like combining factory object with actual data object.
> > This is why __construct/__clone exists - so the object could take care
> > of the details and the factory didn't have to know about it in details.
> >
> > I presume you want to say that Data object should be private class. I
> > think - at least from my partial understanding of the code - that it
> > shouldn't exist at all, especially given you don't want to expose it to
> > the user.
> >
>
> You need to imagine that the entity has more properties of course and
> no, the data class should not exist at all since it is only used to
> emulate something that is currently simply impossible: allow some class
> access to parts of another class while not allowing anyone else access
> to it.
>
> Again our goal:
>
> > Create a builder that builds an immutable entity.
>
> A possible solution as I could imagine it:
>
> <?php
>
> // This is the magic that enabled backwards compatibility and changes
> // semantics of leaving the visibility modifier out.
> (assembly|group|module|package|...) Fleshgrinder\Internals;
>
> namespace Examples\Builder;
>
> public final class Entity {
>
>     //const class = 'Fleshgrinder\Internals\Examples\Builder\Entity';
>
>     number $id;
>     string $name;
>     DateTimeImmutable $created;
>     DateTimeImmutable $changed;
>     SomeValueObject1 $some_property_1;
>     SomeValueObject2 $some_property_2;
>     // ...
>     SomeValueObjectn $some_property_n;
>
>     function __construct() {}
>     function __clone() {}
>
>     // Getters for everything ...
>
> }
>
> public final class EntityBuilder {
>
>     private Entity $entity;
>
>     public function __construct() {
>         $this->entity = new Entity;
>     }
>
>     public function build() {
>         return clone $this->entity;
>     }
>
>     // Setters for everything ...
>
>     // Other useful stuff while building ...
>
> }
>
> ?>
>
> Currently the only way to achieve this is through an interface for the
> entity and hoping that everyone uses that interface and never finds out
> that the class actually offers much more functionality. Or you add a
> shit load of arguments to the constructors. Or, my preferred approach,
> via the magic __set_state method that is not auto-completed via the IDE.
> That approach is still not ideal but one of the best. The problem is
> users who find out that that __set_state method exists and they might
> start using it. The last resort are hacks ... more about that later.
>
> On 8/15/2016 12:11 AM, Stanislav Malyshev wrote:
> >> Another example that is not solvable with friend classes would be the
> >> strategy pattern of hidden strategies as we find it for example in
> >> Symfony's process component.
> >>
> >> https://github.com/symfony/process/tree/master/Pipes
> >>
> >> The pipes are purely internal to work around differences between PHP on
> >> Unix and Windows. They are not meant for consumption through users, they
> >
> > Sure, they aren't useful for most, but I see no problem in somebody
> > using them if necessary. Say, you may want to use Unix pipe on Windows
> > because you are in unix emulation environment, or you have a weird OS
> > that is not Unix and now Windows and want to reuse parts of these
> > classes to deal with it. There could be many cases we can't foresee when
> > we design it for our ideal use case.
> >
>
> The joke is, you cannot do that. Both the Process and the ProcessBuilder
> do not allow you to change the Pipes that are in use. Unless you hack it.
>
> https://github.com/symfony/process/blob/master/Process.php
> https://github.com/symfony/process/blob/master/ProcessBuilder.php
>
> These are purely internal classes that serve a single purpose.
>
> On 8/15/2016 12:11 AM, Stanislav Malyshev wrote:
> >> At trivago we have hundreds of applications, packages, libraries and
> >> developers who work in a very fast moving environment. Reading
> >> documentation is not something most people spend time with.
> >
> > I find so many things not right with this statement I don't know where
> > to start... So I just leave it with a note that having no time to do
> > things right usually means doing things wrong many times, and *then*
> > being forced to spend time to do things right because the whole jenga
> > tower crashes on your head. That is not a criticism of you or your
> > employer, but rather the result of experience learned the hard way. You
> > can get away with it from time to time, true, but it's just luck.
> >
>
> Thoughtful API design is bad? Pretty much any- and everything in PHP is
> a breaking change because many things cannot be restricted. The addition
> of visibility modifiers to constants in PHP 7.1 is a blessing because as
> of now any change to a constant is directly a breaking change. This
> sucks and only helps to increment the MAJOR part of our SemVer version
> strings. Of course it also means that we need to touch a bunch of
> packages because our composer is restricted to ^1.0 and now needs to be
> ^2.0.
>
> On 8/15/2016 12:11 AM, Stanislav Malyshev wrote:
> >> It's also easy to work around property and method access modifiers.
> >> However, that is no argument to remove them now.
> >
> > Not very easy. The only way to work around private is to use heavy
> > machinery like reflection. This is why, btw, private should be used very
> > carefully - when if you're *sure* nobody will need or is advised to
> > access that thing directly. Overuse of private, especially for methods,
> > leads to classes that are not extendable without horrendous amounts of
> > copypaste.
> >
>
> This is not true, closures are a lightweight work around here.
> Nonetheless, heavy usage of private for methods does not make much sense
> in any context or programming language but it does for any other kind of
> member (we are left with constants and properties).
>
> On 8/15/2016 12:11 AM, Stanislav Malyshev wrote:
> > Also, there's a difference IMO between classes and class' properties.
> > Class details may be - indeed, need to be - hidden because this is what
> > the class is, one of it's reasons to exist - a tool to reduce complexity
> > by hiding irrelevant information and exposing only relevant information
> > as class' public API. You hide things not because you're afraid evil
> > users would abuse them - but as a service to the user to not overload
> > their mental models with irrelevant details and allow to deal with the
> > class by only considering the important things.
> >
>
> Now exchange class with package in the above paragraph and all of this
> is equally true.
>
> On 8/15/2016 12:11 AM, Stanislav Malyshev wrote:
> > However, if we're talking about collection of classes sharing a
> > namespace, there's no such thing as "namespace's API", at least not in
> > common use. There's a concept of library's API, but it's not derived
> > from classes alone - it's usually what documentation does, while class
> > API can be yet figured from it's methods, library API is usually
> > impossible to figure out just looking at the classes - you need the next
> > level, documentation.
> > So in my opinion, if you hide some classes from instantiation from
> > outside namespace (which by itself carries a lot of assumptions, such as
> > every class that will ever need it will share the same namespace),
> > reduction in complexity is almost none, since nobody uses "list of
> > available classes in package/namespace" as a way to work with the
> > package anyway.
> >
>
> A namespace might not have any relevance for you but it has to the PHP
> community at large who are using PSR-0/4 and Composer. All of my
> namespaces start with Fleshgrinder and all of trivago's namespaces start
> with Trivago. The same is true for Symfony, Drupal, Laravel, Zend, ...
> so yes, my classes share the same namespace and they will always share
> the same namespace unless someone else starts using my namespace.
>
> Also your last paragraph is completely untrue. Every time one interacts
> with the IDE auto-completion a listing of all available declarations
> that fit the context is given. Hence, if I type `new ` followed by a
> Ctrl + Space everything is being listed. The only thing I can do now is
> adding a filter by starting to type a few characters.
>
> Your approach of making everything public from the very beginning means
> that you add everything to your public API. It also means that you need
> to support everything in a backwards compatible manner. What does that
> mean for us as library developers?
>
> Traits are the worst since we cannot change anything.
>
> Interfaces cannot be changed in any way other than moving members up
> into another interface that we extend but the other interface is not
> allowed to add any other members to our interface.
>
> Classes cannot be changed in any way because someone might extend them.
> We cannot introduce new members since extending classes might already
> have them. We can however introduce new private things and fiddle around
> with magic methods to some extend.
>
> Final classes give one more freedom but are a pain for people who like
> to rely on mocking and learned what interface explosion means.
>
> It is about API design and not only about class API design. It is a
> combination of documentation and modifiers.
>
> On 8/15/2016 12:11 AM, Stanislav Malyshev wrote:
> > P.S. BTW I still don't know why you need to refactor namespaces to have
> > namespace-private classes anyway. Isn't it just a matter of the match
> > between current scope and target class name?
> >
>
> This is better explained by nikic and others.
>
> --
> Richard "Fleshgrinder" Fussenegger
>
>


-- 
pozdrawiam
--
Michał Brzuchalski

Reply via email to