Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:116208 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 91813 invoked from network); 4 Oct 2021 08:14:21 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 4 Oct 2021 08:14:21 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 89F621804C4 for ; Mon, 4 Oct 2021 01:58:31 -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-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-ed1-f52.google.com (mail-ed1-f52.google.com [209.85.208.52]) (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 ; Mon, 4 Oct 2021 01:58:31 -0700 (PDT) Received: by mail-ed1-f52.google.com with SMTP id p13so33801103edw.0 for ; Mon, 04 Oct 2021 01:58:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=8OTGm61bvn8ZGEBT9P2elBgg0esT1mDCx1TIPYub69M=; b=e9PPoahFtjqmeYpDeZZN09zJLO+MdahzuluKxwmM+cEaD9HfbR+YcLLTQXBs3gzlQg ghucSCzmOxJQuuDD3YZft4EQJmqEqnsaTnKsE1Iu5Paz5UZcNOt+OBMiNBcfluU39ajc KZF46s9g5dPyYs4i/ywAefG/307189SL7pKJr7g0YJE0SmmgcX+kCORsr3X+jSeBVTDx kPYGzXJRp/etGo17GYpqt+XV8gvZ3uqfhI8/+SlVyNnZCsN2f3V+WuYTgfgPqU7ZmFH6 sXJuLYBCwFANDibeQu6vStph98dMgyRkr6LjsAviobZeSW/Us1RGVIgazD1B2ybfI+Sq 2dSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=8OTGm61bvn8ZGEBT9P2elBgg0esT1mDCx1TIPYub69M=; b=n18T2YotZODNuqrCnNHvFelPYsj0xSBuxld18Ym1YZZF9b5SaS8LLvRteI8U219ct5 6AyA3O/CWfQNL57WJ+qOs+fLCg3FetHMpCUHT2nDxc/rWLZVoUQHbhPBBQ2A4EaD41Hn qVvotM+6WWycGrwT+sfUQreHne0zuVTgVss0S+Oyr4k02zb9mgDidrfbAat6O3IA/d2l Nz6WBzGzh30LXEcroAKCZNKIGluKtzvMMvt8hlEYQ5NZt9wNnYGMByDqyBqvjnVCpXBu hDriFei329MLzDls+e93Eru94EUTw4c1w4EhieRV0b7vJ0YMOD1A4RyHbQ++RWjMVbOl +V9w== X-Gm-Message-State: AOAM533GMTfpUKQKssBhB+SVZWAUVDfN/C9r84PcpY1/Uam67mrswtwJ GvcsxsklyYZvhqaK0Pojm9WiHvyuOgPjq71KqE4Zu84D X-Google-Smtp-Source: ABdhPJxJt9jryYVzZuBsHEDc1i2Kn6GadFezV/weCB8G4Mo1pJbB2uMcOqoT1GXy0Te2stgzFW4neHqBBo/fKLdZd/w= X-Received: by 2002:a17:906:2b53:: with SMTP id b19mr11467626ejg.339.1633337905815; Mon, 04 Oct 2021 01:58:25 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Mon, 4 Oct 2021 10:58:09 +0200 Message-ID: To: Andreas Hennings Cc: PHP internals Content-Type: multipart/alternative; boundary="000000000000aca42505cd831db9" Subject: Re: [PHP-DEV] Static (factory) methods in attributes and initializers From: nikita.ppv@gmail.com (Nikita Popov) --000000000000aca42505cd831db9 Content-Type: text/plain; charset="UTF-8" On Mon, Sep 27, 2021 at 5:58 PM Andreas Hennings wrote: > Hello list, > > currently, the default mode for attributes is to create a new class. > For general initializers, with > https://wiki.php.net/rfc/new_in_initializers we get the option to call > 'new C()' for parameter default values, attribute arguments, etc. > > Personally I find class construction to be limiting, I often like to > be able to use static factories instead. > This allows: > - Alternative "constructors" for the same class. > - A single constructor can conditionally instantiate different classes. > - Swap out the class being returned, without changing the factory name > and signature. > > In fact, static factories for initializers were already mentioned in > "Future Scope" in https://wiki.php.net/rfc/new_in_initializers. > However this does not mention static factories for the main attribute > object. > > For general initializers this is quite straightforward. > For attributes, we could do this? > > // Implicitly call new C(): > #[C()] > # Call the static factory instead: > #[C::create()] > > So the only difference here would be that in the "traditional" case we > omit the "new " part. > > We probably want to guarantee that attributes are always objects. > We can only evaluate this when somebody calls ->newInstance(), because > before that we don't want to autoload the class with the factory. So > we could throw an exception if the return value is something other > than an object. > I was also considering to require an explicit return type hint on the > factory method, but again this can only be evaluated when somebody > calls ->newInstance(), so the benefit of that would be limited. > > The #[Attribute] annotation would allow methods as target. > > Reflection: > > ::getArguments() -> same as before. > ::getName() -> returns "$class_qcn::$method_name". > ::getTarget() -> same as before. > ::isRepeated() -> This is poorly documented on php.net, but it seems > to just look for other attributes with the same ->getName(). So it > could do the same here. > ::newInstance() -> calls the method. Throws an error if return value > is non-object. > > we could add more methods like ReflectionAttribute::isClass() or > ReflectionAttribute::isMethod(), or a more generic ::getType(), but > these are not absolutely required. > > We could also allow regular functions, but this would cause ambiguity > if a class and a function have the same name. Also, functions cannot > be autoloaded, so the benefit would be small. I'd rather stick to just > methods. > I see where you're coming from here, and I think an argument could be made that our attribute syntax should have been #[new C()], allowing us to associate arbitrary values -- which would naturally allow the use of static factory methods once/if they are supported in constant expressions. As that particular ship has sailed, I'm not convinced that supporting static factory methods as "attributes" would be worthwhile. It's a significant complication to the system (that users need to be aware of, and consumers of the reflection API need to handle) for what ultimately seems like a personal style choice to me. Do you have any examples where using static factories over constructors for attributes would be particularly compelling? Regards, Nikita --000000000000aca42505cd831db9--