Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:113518 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 53369 invoked from network); 14 Mar 2021 16:37:47 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 14 Mar 2021 16:37:47 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id DC3261804C0 for ; Sun, 14 Mar 2021 09:31:03 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-Virus: No X-Envelope-From: Received: from out3-smtp.messagingengine.com (out3-smtp.messagingengine.com [66.111.4.27]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 14 Mar 2021 09:31:03 -0700 (PDT) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 8B1875C00BA for ; Sun, 14 Mar 2021 12:31:02 -0400 (EDT) Received: from imap8 ([10.202.2.58]) by compute4.internal (MEProxy); Sun, 14 Mar 2021 12:31:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=ANFztD gEGeLfRwuApWaPi6BhyPtcJwIFFo7CQPHTNTk=; b=GEjhvwtyMeVZ0SZV1P/iKv +KHgLscd7eVWBbpLfLdrTYim29L7neDRgw9CMxQle97E6Vd0f6GstZO3WK+rot65 ndZM5riwjOfj3wwgSuHP/Xx9JWUSmGvkMYCG/YwUzuIgqXPU/H8g3L06qjdg6t7A 9WuScekasqHhMcy9nQUu5Hx2PI4f5PQVIkNu8kZN63KOS/osUP1UhC1p4p7HDq15 0vjthk9TQ7hGllu2P8okuzPum4aC5oBg2/Mv6CgHVgaM6l6zSFxgNjcuK+l1L9zZ mufsnP8NHCeBIlSmGHFxTL/j3rWushX8Y4UYt92l/XYXuqvIfOxuf6eyDfoU73jA == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledruddvjedgieegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvffutgesthdtredtreertdenucfhrhhomhepfdfnrghr rhihucfirghrfhhivghlugdfuceolhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtoh hmqeenucggtffrrghtthgvrhhnpeekteelheffgeefvddufeeujeekhfdvtdeuuedvveet ieevheeludegjeduhffhteenucffohhmrghinhepghhithhhuhgsrdgtohhmnecuvehluh hsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomheplhgrrhhrhiesghgr rhhfihgvlhguthgvtghhrdgtohhm X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 208243A0433; Sun, 14 Mar 2021 12:31:02 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.5.0-alpha0-206-g078a48fda5-fm-20210226.001-g078a48fd Mime-Version: 1.0 Message-ID: In-Reply-To: References: Date: Sun, 14 Mar 2021 11:30:36 -0500 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] Built-in decorator attribute? From: larry@garfieldtech.com ("Larry Garfield") On Sun, Mar 14, 2021, at 7:33 AM, David Gebler wrote: > Hi Ben, > I have been looking at your #[Deprecated] PR to get an idea of where to > start with implementing this, I think Peter's suggestion of how it might > look syntactically is also interesting - it's exactly that sort of question > of how would you imagine devs implementing and using decorators in PHP that > I wanted to get a feel for before I started trying to build it or draft an > RFC. Your other tips regarding zend_observer and zend_call_function are > much appreciated, saves me a lot of digging through the source figuring out > the appropriate APIs for myself. > > Before and after hooks are a similar but slightly different implementation, > semantically, to what I was originally suggesting but may be the preferred > option. I think to be useful, you probably still need some way to choose > not to call the original, decorated function - but I guess you could just > throw an exception in your before hook and that might be sufficient control > in practice. > > Regards, > David > > On Sun, Mar 14, 2021 at 11:52 AM Benjamin Eberlei > wrote: > > > > > > > On Sat, Mar 13, 2021 at 5:51 PM David Gebler > > wrote: > > > >> With the introduction of attributes in PHP 8, this new behaviour is still > >> quite sparsely documented. Some of the articles I've seen out there, > >> though, liken PHP's attributes to similar constructs in other languages > >> including decorators in Python. > >> > >> Attributes are not the same thing as (Python's concept of) decorators and > >> they shouldn't be confused; a decorator is a function which wraps another > >> function and is automatically called in place of the wrapped function. > >> > >> This isn't currently possible in PHP. Using frameworks like Symfony, we > >> can > >> start to build things like this: > >> > >> class UserProfileController { > >> #[LoginRequired] > >> public function editProfile(...) { } > >> } > >> > >> but the logic of enforcing our "require the user to be logged in" > >> decorator > >> relies on the surrounding framework controlling the flow of execution, > >> reading the attribute and deciding whether to call the decorated method > >> editProfile() at all. > >> > >> What we *can't* do is something like this: > >> > >> class Foo { > >> private function timer(callable $wrapped) > >> { > >> $start = microtime(true); > >> $wrapped(); > >> $end = microtime(true); > >> $total = $end - $start; > >> echo "Executed function in $total second(s)\n"; > >> } > >> > >> #[timer] > >> public function bar($a, $b) { ... } > >> > >> #[timer] > >> public function baz($a, $b) { ... } > >> } > >> > >> What I'm wondering is whether there's a desire / interest for a built-in > >> attribute to provide this kind of behaviour modification. > >> > >> I'm thinking something like > >> > >> class Foo { > >> private function timer(callable $wrapped) { ... } > >> > >> #[Decorator([self::class, 'timer'])] > >> public function bar() { > >> echo "Bar"; > >> } > >> } > >> > >> Where this would result in any call to $foo->bar() being equivalent to as > >> if the above were defined as: > >> > >> class Foo { > >> private function timer(callable $wrapped) { ... } > >> > >> public function __bar() { > >> echo "Bar"; > >> } > >> > >> public function bar() { > >> return $this->timer([$this, '__bar']); > >> } > >> } > >> > >> I'm not saying I have the skills to implement this attribute (though I'd > >> happily try), I'm not even in a position to propose a draft RFC at this > >> stage, just throwing the idea out there to get a feel for what people > >> think > >> of the concept? > >> > > > > In my opinion it would be a fantastic addition to Core to be used by > > application frameworks with "hook philosophies" that hack this > > functionality on top of PHP with code generation or event dispatchers at > > the moment (Magento 2, Drupal, Neos, Wordpress and so on) makes this a > > potential future with wide adoption. If you'd get 2/3 votes for it is > > another topic. > > > > However, as functionality it could be provided as an extension first for a > > proof of concept. The ingredients are all there, it doesn't need to be in > > core: > > > > 1. Register an internal attribute, see my #[Deprecated] PR as an example > > https://github.com/php/php-src/pull/6521 > > > > 2. Register a zend_observer as a first step, that detects > > functions/methods with a new #[Intercept] or whatever attribute you want > > and registers observer callbacks. See ext/zend_test > > https://github.com/php/php-src/blob/master/ext/zend_test/test.c or > > tideways/php-xhprof-extension: > > https://github.com/tideways/php-xhprof-extension/blob/master/tideways_xhprof.c#L30-L57 > > > > 3. Use C API zend_call_function in the observer to call your interceptor. > > > > Cobbling this together as a Frankestein monster from existing code should > > be achievable even if you haven't worked with PHP core yet imho. This could > > replace the php-aop extension that isn't maintained anymore. > > > > Using a zend_obserer would only allow you to register a before and after > > hook, the alternative with a "$wrapped()" would be significantly more > > complex with the existing building blocks. > > > > Hooking into zend_exeute_ex would allow you to implement around handling, > > but at this point is not recommended anymore, because its incompatible with > > JIT and might be removed in the future. > > > > > >> > >> Regards, > >> Dave I've been toying (mostly mentally) with the idea of using attributes for guard rules on object properties and function parameters. Benjamin gave me basically the same answer. :-) It sounds like both that and AOP-attributes reduce to the same core problem: Allow an attribute to specify a caller that intercepts an action being taken (call method, write to property, hell maybe even read property although that seems less useful). So, what's the minimal surface area needed in C (either core or an extension) to allow the rest of that to be done in user space? --Larry Garfield