Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:103354 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 82556 invoked from network); 22 Oct 2018 01:28:23 -0000 Received: from unknown (HELO mail-io1-f48.google.com) (209.85.166.48) by pb1.pair.com with SMTP; 22 Oct 2018 01:28:23 -0000 Received: by mail-io1-f48.google.com with SMTP id p83-v6so3994619iod.12 for ; Sun, 21 Oct 2018 14:42:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=tPdop0vfAO+Rdw24fwamZvP4Et46KvvrV0xsq5rsxX8=; b=jbeDoJ7s7JgJwBH+m3vgnA/ISV4QW9546BntKmV/zNtiiLY8UfgH/qTHKt8G4q3sZ/ WAF5CG2+QcbDPXG4uKf8dt+KBPfNHvEyz6NnHJsHKxnOQpOSFLUMoEm8RI9JRJueOziN DybjAYMrtlKcvRCWjQxlaF35wRDpUxz5h44xowhayR40AdROWHWAa320xMbscwYWysJ4 CMlGNYMAsyEqiT0PTthpmdtZ+ifBAMrCwo7OscyME4bgAbB6++tf4ZUhJg5obxoZSeaL vXEkx+m7Z23LczqSyZHiiIZt146UiF2UGB7PrZvqylGjIt2+JWppRmj+6dipJ2hRL3DX jCXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=tPdop0vfAO+Rdw24fwamZvP4Et46KvvrV0xsq5rsxX8=; b=FQvZaHJsaQ6y+Jdpu5+3IpzjNTD/EDOEbb/7yZO+rSFhWKBb4MvN0s9IPOICROMVu4 zlHfuC/GKJPLDSGC6AtWGhTW+Xdq/5shdQv+SOw7nYhOyJTuDTv/Y95xl7TkDE0EcAi0 FvOp5nkmT44W0RP1kafHy+t/oHi3jq8jv2LFPcF0yy4gREriiTCy8nzOp2i+nyO8iTaf bsaDNu90HhDwSL+DvTr87/HaC0ELHBhg6COplWAov0r3Szp6iW+qcZCNOIb7nZVgOHVb UrTvXU7BYmg1/8k8t+TvomHC5X7eJ2/7yOwnrgEKKNuN5dAtFdw0c4ZpgJV/26YyQzmI 74/A== X-Gm-Message-State: AGRZ1gIvKngpaj6WtlUluIACTCiCszAEEl37/F4C+kTDewUj55M4BjWX h3rGvGKRKYQAuK+Ibh22+X4NTnFxq/JhLvsfQlQ= X-Google-Smtp-Source: AJdET5d69jVXvEVYoTdyKUW1YHmeoNcL9OsPdsr2v3yezgCZqMRR79ZrU4RQSMnDck8fk8F1FID6vYkESkr4q875EFU= X-Received: by 2002:a6b:e415:: with SMTP id u21-v6mr8121587iog.78.1540158171540; Sun, 21 Oct 2018 14:42:51 -0700 (PDT) MIME-Version: 1.0 References: <0047f3c7-3e9e-ef6f-2d7a-e58c316ea751@gmail.com> In-Reply-To: <0047f3c7-3e9e-ef6f-2d7a-e58c316ea751@gmail.com> Date: Sun, 21 Oct 2018 23:42:39 +0200 Message-ID: To: Rowan Collins Cc: PHP Internals List Content-Type: multipart/alternative; boundary="000000000000b673aa0578c404de" Subject: Re: [PHP-DEV] Composition over inheritance: native support for "delegating" methods? From: ocramius@gmail.com (Marco Pivetta) --000000000000b673aa0578c404de Content-Type: text/plain; charset="UTF-8" On Sun, Oct 21, 2018 at 7:41 PM Rowan Collins wrote: > Hi, > > I've been thinking about how the language could better support > Composition patterns like Decorators and Proxies, using some simple > syntax sugar not dissimilar to Traits. > I do not think that this syntactic sugar is needed: * If you have few methods, writing the delegation code is trivially done, tested, statically analysed. * If you have a gazillion of methods, *something is really wrong* (you can't decorate something with ~5+ methods without introducing some unexpected side-effect - that code is already a bit too complex). Implementing this proposal to aid those scenarios is probably aiding bad API design. * If you need to proxy and add behavior, userland libraries already exist (mostly `doctrine/common` at https://github.com/doctrine/common/tree/a210246d286c77d2b89040f8691ba7b3a713d2c1/lib/Doctrine/Common/Proxy, `goaop/framework` at https://github.com/goaop/framework/tree/2.2.0 and `ocramius/proxy-manager` at https://github.com/Ocramius/ProxyManager/tree/2.2.2): if you aren't happy with those, a bit of `ReflectionClass#getMethods()` grunt work is just fine. We're still talking about edge cases anyway. * If you are proposing this syntax for performance reasons, most current delegation code has almost no noticeable overhead besides a new stack frame (possibly something the engine could optimise), and when it is present, it is to avoid I/O (much heavier anyway) Example: > > class SpecialSessionHandlerDecorator implements > \SessionHandlerInterface, SpecialInterface { > private \SessionHandlerInterface $delegatedHandler delegate { > close, destroy, gc, open, read, write > }; > > public function specialMethod() { ... } > } > One problem with delegating calls this way, is that any new method implemented by an ancestor will not be delegated by default. A better solution would be to have a single `delegate` keyword that intercepts all method calls for methods not declared in this class, as if `__call` was implicitly implemented: class SpecialSessionHandlerDecorator implements \SessionHandlerInterface, SpecialInterface { private \SessionHandlerInterface $delegateHandler delegate; public function specialMethod() { ... } } If you don't do it this way, you end up with a BC break any time an ancestor defines new public API. Yes, in this case these are interfaces, so it would already count as BC break, but if the parent is a class, adding new methods becomes a BC break as soon as the class is not `final` (I described it more carefully at https://github.com/Roave/BackwardCompatibilityCheck/issues/111 - missed to add that check there, so I'm glad that this issue reminded me of that). Still, even if you do it this way, implicit delegation of any newly added API may also not be wished, so it is an open-ended question. Anyway, I do think that: 1. the language already has all the tooling required to implement decorators correctly 2. the addition of a `delegate` functionality would cause more confusion for something that is already really trivial to implement/test/read The suggestion requires some stronger foundations/reasoning in order to be turned into a valuable RFC. Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/ --000000000000b673aa0578c404de--