Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:113513 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 35956 invoked from network); 14 Mar 2021 12:40:42 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 14 Mar 2021 12:40:42 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id C4B321804D0 for ; Sun, 14 Mar 2021 05:33:57 -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.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,HTML_MESSAGE, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-Virus: No X-Envelope-From: Received: from mail-oi1-f169.google.com (mail-oi1-f169.google.com [209.85.167.169]) (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 05:33:57 -0700 (PDT) Received: by mail-oi1-f169.google.com with SMTP id d16so22512940oic.0 for ; Sun, 14 Mar 2021 05:33:57 -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; bh=UFDG8HjJg2cnxCyVO9f1q3ubtzaxjq7idx4dxFZbucs=; b=eIehAxpYEthRhoACogp4SDMl8As6Cu8M3luOobhc3auQA5iCORDXqKHZws5vVR9sK1 3kTJqn2lyoBTzmlCQBPlzOlLE22aI9T64PVcsTWlT6AaoJd/fASSyEbbO25KNfC+KL6Y uGJDuZh3ONvNsPIj9s/gOWhGNsApV1GAAKACgdIAWgo/rB/f5x8Zj+MRpYzHy0HGWspf hDOdBJ5vKLExrJq6hf1Z5/MqncnoTL45A3jX0nv/fmzlv1CbXRMtscHBgj7X7zlcOeH1 dm9JXkryw+xBIxD87uUaopYo9qcST9RjDkAQPpeUaW+OdrRWC4pZnYFB6jhkMlNSe0EG 0A7w== 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; bh=UFDG8HjJg2cnxCyVO9f1q3ubtzaxjq7idx4dxFZbucs=; b=DdhGgNX/acOt0iAOKNqUb26o4wgNTMvAsr5d9MNt4sU0HrEtj5KXPNyDBofumI19d1 vfKKUELrwdAXM8Twxqwxln1hl5VVSQXIlyEGudiXwOH8MmXHMa/ikr1jvaSNQgNuPVP8 8x/bRix77zevgXkZHsDIBHuuscoOIRe+Wofn2gPKdfYJZSMg/TB9mJFVwcV2nt96CdIW L104QftX33gW3OwRE05GHHZp7aUOLmyPA0vhOhYB4+0oju69aCGUH/IBax0pjzGttsgN lm4CW62oMz7sNMBbGh52JnzrYsw08/UcNbJdDfJ1OzOVMpZ4gMl/pnY9a1UIvZvAOqLK SGSw== X-Gm-Message-State: AOAM532MBE+SkhT8FdEJMzRZ85DeMpxYWJgdNJMpCjVgkZRX6CZ4bdDq 6rfJp6IfpX+3SlpTeOI6UCRAmkzMs3NCJ2NiDqu+ql8RhQk= X-Google-Smtp-Source: ABdhPJzgVH5lSUg1mMUUkNn8sN1x6Euj5QR4T8rmH96SHZL6Az9Ht6f3SX98G6cqp1kdvVapVG+ilHyQJby0bas7eRA= X-Received: by 2002:aca:59d7:: with SMTP id n206mr15505885oib.7.1615725234659; Sun, 14 Mar 2021 05:33:54 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Sun, 14 Mar 2021 12:33:44 +0000 Message-ID: To: PHP internals Content-Type: multipart/alternative; boundary="000000000000aaa54c05bd7e5803" Subject: Re: [PHP-DEV] Built-in decorator attribute? From: davidgebler@gmail.com (David Gebler) --000000000000aaa54c05bd7e5803 Content-Type: text/plain; charset="UTF-8" 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 >> > --000000000000aaa54c05bd7e5803--