Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129496 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id 5E06A1A00BC for ; Mon, 1 Dec 2025 23:04:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1764630299; bh=kZOf3g/BIOxHqSlP77I11ToU7pBGee/CSkcHbU5mlx4=; h=Date:Subject:To:References:From:In-Reply-To:From; b=KrIcSyCiONdfUtZKlqrjNEnvIAcSCwSH2Bt5beNFTM7T7PwVrQxS7MSuG0nAFXwZX PY028OxS3fY4C3arDHCDXqiYGISUo8k3OCTgqW5L0h8/GeVQPqsySXN/Jv964fUYWL FPxVF2Xt08xwjtJ4GIMwnzBBjh/HItfyJisTgXftBZMFDbctjCXh+tgh6b1hbOjptu 8jJeOR7fO1g+H9RCXRnpAeAzNjxm+IJO9Hk1t5rK8fy4p1M4LC7cPwOfgFLVnSLrAM tlndNbJPlPSl2U//nkVp1GH3MAnwGAqyT3CeXkrIbM4jpaTvVqPfkmgZjnVv009WCD TmaAMf3RFnBOw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 7E0B01801D8 for ; Mon, 1 Dec 2025 23:04:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.9 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_50, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS, FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,HTML_MESSAGE, RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from AM0PR02CU008.outbound.protection.outlook.com (mail-westeuropeazolkn19013087.outbound.protection.outlook.com [52.103.33.87]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (secp384r1) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 1 Dec 2025 23:04:58 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=hRvzcc1RHPxMsGjKBxlI8MdvvBpEfPaZpxNtJhd+f5cnLaRkqQZugpvt64MkLGD7uuIxdHmyfj5bBEXv4o7GQKD3R5Ft/1zoxibrmDbG4qO6vLnRNxWFq0FU0Al2cThun5Ywl/+/TU+6DtIa9MZ+drXdsPA2SlwIBd37s1AB4JU2YormpNKSy5b5DSF7qJI7ZLjGZgcKEC62vbDIDvPfrDbRE9IA4wABvKXDA+im47UrxDzAqGeUUQL/nc/k4rTPnbQvB5vXHv8q/IglDbU9zCRkAOc+qvYScugC2O+K5KUWsh5QFwWmS9iFyQAf1Kmo8TB6TuqxfMzNdfdMunpo/A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=7hY4+PkhwgRO/YJs2kcdY8nq+Hixha87g4BBkqTAKt8=; b=rP6CfGZvZuBcIdSVG/zYnZX9BbENd6VsT4rAQDd1xUz0BA/REEGHbSMAsfPyBn7dG4/3S6Xut3ynrZyYX9zruleEYZ1fuLriSQA2CH20FetCUCYnZ2J63VJ1BYnrFEKRytjshS96s4eOVaha7jhIQAh7mKvYk17v9PcGXiY2yX64z6B9bbX/xWlRVKSAlSQC3cm9/cFMbdQxPfNPMrtZh3pKHD8DOO9Nj0GWc0rcXK0js7en21nySS2mUlQjNEqGYdLGiJiC4cY0UDhG2HjyL3atSkJwFoVcwaiv8HbOyTy5375YJuqKEm5jnqwJ2Kxw/wP3DjoC1bwyx/+8pK2EBw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=hotmail.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=7hY4+PkhwgRO/YJs2kcdY8nq+Hixha87g4BBkqTAKt8=; b=WIFYsil9twBUrzQ60rRYgyNG63kMjfKVN+vS1rlywzpegM049i9UU8qtKX8qeNP0GArElRvZclJeUAdMyI32DnTsSWAfRI0830a88vZdngxUB9jv28ofa/7XAzDxkHZYXqLdzUD5gdp9QbGpUXgpBVo7xYdP0pdFA3qIBMSeW6MbcO2AHMoush69TQjESfJfk5GdD1qaVBWn8HmbtSLRPklxfEo7n8X1aohgCJj7GKpJYXACv5N47Ige0O47ma5+p3PcwS+IZeTPolk876nUmp2a9SgHHAHaNxkGQz6C+hdLquCwK7qdNoKumDkSAreqb7IyF6XBjHz8NtEspALr8A== Received: from AM8P250MB0170.EURP250.PROD.OUTLOOK.COM (2603:10a6:20b:321::21) by GV1P250MB0834.EURP250.PROD.OUTLOOK.COM (2603:10a6:150:9a::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9366.17; Mon, 1 Dec 2025 23:04:50 +0000 Received: from AM8P250MB0170.EURP250.PROD.OUTLOOK.COM ([fe80::651e:bbd2:b18a:80ff]) by AM8P250MB0170.EURP250.PROD.OUTLOOK.COM ([fe80::651e:bbd2:b18a:80ff%3]) with mapi id 15.20.9320.013; Mon, 1 Dec 2025 23:04:50 +0000 Content-Type: multipart/alternative; boundary="------------EA0eJDUXohJ09za01rsTco6X" Message-ID: Date: Tue, 2 Dec 2025 00:04:49 +0100 User-Agent: Mozilla Thunderbird Subject: Re: [PHP-DEV] [RFC] Pattern Matching To: Larry Garfield , php internals References: Content-Language: en-US In-Reply-To: X-ClientProxiedBy: FR0P281CA0085.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d10:1e::9) To AM8P250MB0170.EURP250.PROD.OUTLOOK.COM (2603:10a6:20b:321::21) X-Microsoft-Original-Message-ID: <5e8ca40f-2b9c-421f-9ab0-4ee197599127@hotmail.com> Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AM8P250MB0170:EE_|GV1P250MB0834:EE_ X-MS-Office365-Filtering-Correlation-Id: bf9a05ec-e94e-4863-be8f-08de312e07c4 X-MS-Exchange-SLBlob-MailProps: obhAqMD0nT9fvh6/tC8lvsVfJ8vEtTE5T6IDH2iKcmh4YCoY5eOf0mEHF7Dis7rPkQ5CU8sMWXUdqpPiHHl8o8AuYCj8wi8uwWxWvXw0Lgjm7vUZrx9DDRkNhrHeSzCjgNJugwO1PG+CxONF0m/BhM4RCg7Ji5ke0gjwf/VOnNPGB/dcrFP7hUBeUJ/yVns36FMl18Qr7CWqgrUrF7mLxjdks4/TIbA1zrTa0+st35PEvki2Xu34MzidPcqTDsGqmSb4CyYZ/ig7OlgTIKHrqMqQPGfGAYkCCPsog+tmJuj+pHIsujyo8IWJ6AO13URLAnSzCjePPapB041JEw2aguuc5PCXrjbCpXLJq3Q2O7D2fwPb5284VExp4vILUHVdpUKUBid/nbxHbsPJ2WA43xTVDZsPgwzzBaK8/fGCQlFGvZ96OtiQsXmWGjvMkqFInuXAFG/Id+I/hkZU7kxV8fM6n2z2Y9s6yAiEFpcJFXBa3PmhAioi2zVHzu41jNBXS0pTXcsy+OmZ6ddznI3+2CdB7dY6NQPRR+q/IQR0KwfNBs7p+IlSHwnVDOTnfukfcBeUObS3UIswr8bFF2rb6lPSypN/uye6VbQXqzbcDsZ7ApYacgj6fP5bCISACyF9Vb+nAAVcpDjy3oC3cUps2DdAT5YgDu2Z82zmI3y1GrMI20GG8Vqlr4ATSfANL82HareFyZLfIeDO4ropMyLwQax9ddLMyYgtnqzCSCwaev9BHTmqq3/dGy/rmPwiMvrHZAPQi+P9pmsskNn8OZGayUCBzlIkzjnuTVX9cKdkg6DUJ/q+vcp0O8R5QqEECfn7 X-Microsoft-Antispam: BCL:0;ARA:14566002|461199028|51005399006|19110799012|12121999013|12050799012|8060799015|23021999003|15080799012|9400799040|41001999006|5072599009|56899033|1602099012|40105399003|4302099013|3412199025|440099028|10035399007|26104999006; X-Microsoft-Antispam-Message-Info: =?utf-8?B?MDNRcDRhbzAyRFAyck5TTmUvNnhMTXVGaks0ZE4wQTBqaTZuVUtkckJiRE1X?= =?utf-8?B?MTIzaVBFNVBWNG1EVSs5di85V2N5MnlMVkxPdzFmUzl0eVpocHlXamFKVklQ?= =?utf-8?B?aGVKNTlScWFqN2lKZzZKV2xJTXh4Mkl6R3FFTHRKSndyaVViOFBLUi9nR0hO?= =?utf-8?B?WWk4bnZIb1czZHZiWUVzOHZsT1hkRjgvMkdCc1g5VFdlZ0cza2QxOTNqUE4r?= =?utf-8?B?eHo4QUtRbVh5TFVOa3g1UzlLNXZYV0dpZ3oxYlBhc0k1b0VsaFlnWE5DbEh0?= =?utf-8?B?UDNhNnFRR1MrQk5LbG5raFdDNkRXbWs5eEZEUjlDR3Rid1NXNlIrbWRSZnE0?= =?utf-8?B?cnZHd3VLSUJPaGwxV1o4dklSYmVZend2MGtReHNLbml3Qi9aUXF4Yjd4a2p1?= =?utf-8?B?SVliMDZhTzhrN3lkNUZDVEN2V2pHcks1bll3VTFvVlRaY0tCaUovUlFzalZK?= =?utf-8?B?cS9ISlF6YzZucFJCMC94QndCMmdKaGdtakg4dEkza0xheWQyR0RYQlFwT0li?= =?utf-8?B?ZUMyQUpMM05ubG1oVVVQVzltNTUxNnpsaVV6dU5KWk4rUGxWc2xQeU9FTmZY?= =?utf-8?B?U3c4K3UyTXZmZk1LZXhmVVRsTDRYZWs0RjliVzk4WWYyOU1PNlMyV0Vvdmll?= =?utf-8?B?ZG1LZ1QvajB3NWQ0YTZ3YzVOMHVYMnVvcGRSSDdoRnc2blhEUWVPdE9VNTg5?= =?utf-8?B?VVdsUExKVXJoNnd5UzZiZ0dMSVZmVWd2VlJCbWtuOHJMZzF5NUhDaklXTlhy?= =?utf-8?B?amhmcmtCOGxJaG50SmczRXhIQ2d4eEE0dE9mTmxzTlRzWnRnakw3VmN1WEJK?= =?utf-8?B?K3hoYmdScVhxS3FKMnRHU0tEM3FPbSt2dWdqVmFYRThabHMvbGVzME5jdkEv?= =?utf-8?B?c1ZQM3ZtRVFUUkxYVWhEN2dRNDBpelhOU3lPbjVnd1h3RU9DRDJLcFdvTXJJ?= =?utf-8?B?UHlZOFJJZEo5TmxCSHVhekNGL0pMUUhkcWpDU2FYemFhbXg5V2gvOElxeWZs?= =?utf-8?B?elczSUV3MXJwcktCMFFSeERMZ1FtQXEremowektXYzlYa3ZOcnVmWmJyUGJk?= =?utf-8?B?M1h3Sm9HWFR5OWFpWGcvSk0zaDRYUmFOUGs3YWV6T2Zsb0ZYWnRpajFKeWt4?= =?utf-8?B?MzJrc0VmV3FqaUhzOFpyK2lQVERJWXFZeWRqUW5iOFhxQWU0cEFZS1pDTVJN?= =?utf-8?B?bCs0RkMxVTQzSm4wamVTRDl5TU9VQTRldjR2UmVRYVFCRms3eGlhZjR2YjBl?= =?utf-8?B?aHUzdHJlVm16RHlEdHpmMEVKRitSMGU4RktLVmdPV3lYejlhWCtRRTdpWW9E?= =?utf-8?B?T01TMUxqZ282SGhLaFJwems5M3h2S0gvcktvMUlFYmx4M3piS0lJWXEzWDFi?= =?utf-8?B?bGgvd1NOczlLRmJ4c1ZMVGFGMFB4cytyVUljNjhSRTBqclpuano4T0QrQzJX?= =?utf-8?B?Y1RPTmJiKzBidHlHT3VLTGpnTDc2TE1nS2piOWY3YnJYMmxYc0xsMDZMU3k4?= =?utf-8?B?Uyt1L2RRZDAvcG1tbW5zM0p4b0xaSG5rbDlQU0tXdmlKRS9zRWRKUi95Znd5?= =?utf-8?B?Z0FycnJEUVlWOXh5cUV2N1YwWEhaQWUyWHo4QTdjZCtBUEp6ZVlhRU13TG5O?= =?utf-8?B?QzlKZXd4OElQVmt0TmFkQ2dyK3JtaWVoTFliUnVVdy9hS0tyaU55UE1WL2Ix?= =?utf-8?B?ZnpJd0ZDSFJ0bzNuVnFxVi96UFNRTUZScG42ck1TVlNaZjdURnpvTFFxNHlr?= =?utf-8?B?Nk5PRUtpcHJNNk1kMXUreENqSmZDWDZNb0MzeHgwR3FITk5CTHluYll3Ly95?= =?utf-8?B?eFpNRkxackhpYlRld3JYVnozZGpuTWJ3dmU0cWZhTzJyc2hTb2F6OHJPN0xE?= =?utf-8?B?aXYva0h0Ly80SU9tbHNwUEllTGVLY3l0SVl1U2ZRWTJ5dlZNbUprVkhMN1Bx?= =?utf-8?B?VEhydklGMnE3RU5tTGZBRnJzZnN1N1BqMjRicnBDRmRLODFKeFRwVHcwRlBJ?= =?utf-8?B?ZS9peHRaMmJ3PT0=?= X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?U2tlckFvZGVodWhUMGlHYlg5REs3cnU1eUFTVVNaa1p5T1dJSlVkYnpQQmxO?= =?utf-8?B?VnRxQTRzdTRTRFhnM053emIyamlueDM5elhjNVlVQlBrWVFJd0ZIRmpQV0dl?= =?utf-8?B?SWFNd3V5aUM4NkdUTDRrY09aMURycy80MEZ0UDBYbmZOa2QrT0V0bWVwTDJP?= =?utf-8?B?WWFKQ0V5c0hyL211Q0lZTUpWV0lmeWQwMWZtWHNZS0w3UE1WWlc0RkU1b2pP?= =?utf-8?B?bVoxbmk1M0oxSlVQd3NvZ2RpNjB3aGZ6clJ6eXdwNEk4bEJtT2Z0MWp5TUpD?= =?utf-8?B?TmhPRnBFbnVwZUllUFdMVTVDd3ZRSHRUUWNKRlU4RnBaVFRmZzhmUWZGcitJ?= =?utf-8?B?eGFpWHgweFJVUmZSeDNGb2tZQWp6L2VOTkdBSnhYK3NwRCsxUXgycGRjVERJ?= =?utf-8?B?T1lUSHZMREdIYzZKbmtydVV3TmpKNy9NYlBlNHdkRmJXb2NDa2lYcEw2WE5O?= =?utf-8?B?YmJEWWRwOEFVVUs3dEEvSWxZbThXTmJ4K1N0TnpYdkVLNWhIR1NhWXNRcUcw?= =?utf-8?B?Q2NibkRBSXB2b3RYVWtKNHc4RHZOUjFkeUt5bkxkT3RXRHlJQkRuVzFJS2lv?= =?utf-8?B?T3RmSC9kcXhpUCtVaHNGRmVaU3BuYmtiNlFubkdsSnlTeVMxYmtmQm95MWJp?= =?utf-8?B?QjBuLzFIRVdBV21jZEVwd2tvd1dIQy9IR0dnYW9ISExUZmVQVUJZTlZldEg3?= =?utf-8?B?VlpxMlhZcCt0eVVIdW1Mbm5yNTkvei9tQUh2RE9YSjVDZ3Y0cU9GMlc0MmQz?= =?utf-8?B?ZHU0ZitpUEtGWmhqdkZ4aTNRUTBmRVdmZW9tRGhhbmRCd1Z4aGRiUmRjajJh?= =?utf-8?B?TzFoaHpEM0cySjREVTgyZ2FqSVQwdVZoRVNJeDVMRWI1UUk4SUpkUVhGZEU5?= =?utf-8?B?RUkyQ0wwL3Exa0NBaEQ3VncvZzV2V00zbXhsMldJaXduZ3g0Wmk0RWhRQjJz?= =?utf-8?B?QUNrQUdCSllHZEN5Y3k4dEduZFYySTREb3Y0MnpCYkVYb2lUS3piZUdzdkw1?= =?utf-8?B?ZGM2Z3pwYjdJMTZhclMwRHd3dWJvQkxFVHczeklPL0xXWmlrd3JFUFZSUkxn?= =?utf-8?B?bzAxdzVJc0xHMDY4UGhJUXRUMDJVM1ZGNTREcXdKaXNQS0tDM0lyQnJWU0ZM?= =?utf-8?B?b2Z6ZDhIQzQ2Y0Z4M0g3OXdRWlllL0laQXZ0eDd3TmNJYVp5aktsUVNhOUZj?= =?utf-8?B?aDNrYTJUZkpMTko2MU8rbGlVVkx0QTFLN0trMVJ2c1VQS0g2Q05ZcWIvWGI4?= =?utf-8?B?WlNnd0hvYjZnTmsrSmJiN011cWtkdzNkNE9NS2t0WENCVUY4ZmtmWVdVeVVC?= =?utf-8?B?QXhQTW5jV29OTGhRRWtGcFVLTVBGQ1lQcXJtZHE0cHpRaW9iUEVNckxnLzl5?= =?utf-8?B?QmRsbnlWcUxkQkprU0w0aVRMWlJzVnBWTkpFUzZpSkN3QmJ3TFhSQy9uTnBj?= =?utf-8?B?MTdLZEhmNDdRQmlRUHoxblpVcUF1T09ML3FnckJUR0dBVldRV21vTXdlZVhZ?= =?utf-8?B?NkluSTluTmJZR0FqN0w0dmRXK2M3QStyTXNuSUdnWUR3TEFiNitVcmgvWUZo?= =?utf-8?B?dkl4WW5sa2JuT0dYNDAvMHZkck9MUGgwRGxmQ3BveTJsQXo5bllTM2g3Yit1?= =?utf-8?B?eWo3c1o0UXY4MGhnQnhmMTZKaVI2czc2YlhUeGE2T1RFam5xNlRlSnZrY2hB?= =?utf-8?B?cTdBOG5acStzbFNra2xDRklsdXBMNnpjYkZoSWZMWlBQM2orY2RlTEhPeS91?= =?utf-8?Q?wxJgephn/PpTlJAtUk=3D?= X-OriginatorOrg: sct-15-20-8534-15-msonline-outlook-5f066.templateTenant X-MS-Exchange-CrossTenant-Network-Message-Id: bf9a05ec-e94e-4863-be8f-08de312e07c4 X-MS-Exchange-CrossTenant-AuthSource: AM8P250MB0170.EURP250.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Dec 2025 23:04:50.5634 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: GV1P250MB0834 From: bobwei9@hotmail.com (Bob Weinand) --------------EA0eJDUXohJ09za01rsTco6X Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Hey Larry, On 1.12.2025 22:36:21, Larry Garfield wrote: > Hi folks. Ilija and I would like to present our latest RFC endeavor, pattern matching: > > https://wiki.php.net/rfc/pattern-matching > > You may note the date on the RFC is from 2020. Yes, we really have had this one in-progress for 5 years. :-) (Though it was inactive for many of those years, in fairness.) Pattern matching was intended as the next follow up to Enums, as it's a stepping stone toward full ADT support. However, we also feel it has enormous benefit on its own for simplifying complex comparisons. > > This RFC has been through numerous iterations, including a full implementation rewrite just recently that made a number of features much easier. We have therefore included two patterns that were previously slated for later inclusion but turned out to be trivially easy in the new approach. (Variable pinning and numeric comparison.) > > Nonetheless, there are two outstanding questions on which we are looking for feedback. > > Naturally given the timing, we will not be calling a vote until at least late January, regardless of how the discussion goes. So, plenty of time to express your support. :-) Thanks for bringing pattern matching up for discussion again. ---- I'd like to note that the class-access is very ugly. // Shorthand if ($p is Point(:$z, x: 3, :$y)) { print "x is 3 and y is $y and z is $z."; } The RFC gives as reasoning that the colon prefix is needed for support of positional parameters in ADTs. Sure. That's fine to anticipate these. But what's not fine is using an inconsistent syntax for variable bindings across different contexts. In arrays binding is just a bare variable. In objects it suddenly needs a colon? What. Also, a colon is very prone to being missed in the future with ADTs. Point::2D($y, $x) vs Point::2D(:$y, :$x). Means something completely different, but if you mess up just having the colon there or not, is a serious problem. Can we instead find some solution, which satisfies both and still delivers consistency? An earlier iteration of the RFC had the following very nice construction: $p is Point&{ $z, x: 3, $y } This just worked. It's a Point class, and then it matches the properties of the object. Nice. This also works for future ADTs. Move::Forward&{ $amount }. Then, if there's a desire to actually *positionally* match an object. Then it's logical to use a parenthesized expression, for a tuple. I.e.: $move is Move::Forward($a) Where $a is assigned the first value passed to Move::Forward. Similarly for destructuring without class name no longer works: $json = json_decode($myInput); if ($json is stdClass(type: "store", :$value)) {    // why do I need to know/specify that it's a stdclass?! I'm just interested in the properties. } vs. if ($json is { type: "store", $value }) {    // } This satisfies the requirements of keep the language clear and intuitive: - Any standalone variable is bound. No weird colon shenanigans. The syntax is consistent. - Positional binding is quite intuitively using parenthesis - you construct the enum with Foo::Bar($var) and you read it back on the right hand side with Foo::Bar($var). - It naturally allows destructuring without class name. - It makes it hard to accidentally write something totally different to what was meant. (Also, it's likely more intuitive to users from other languages, like rust, which also has {} for named stuff and () for positional stuff.) Further this particular syntax works nicely with a future scope of object destructuring, akin to array destructuring. As an example: function addVec(Point $p, Vec $v) {   Point(:$px, :$py) = $p; // I already know this is a Point, why do I need to repeat it. It also looks ugly and quite a bit like a left-hand function call. Like... assigning something to a returned reference?   // Or would you do {$px, $py} for object destructuring? Well that's now truly inconsistent.   Vec(:$vx, :$vy) = $v;   return new Point($px + $vx, $py + $vy); } vs. function addVec(Point $p, Vec $v) {   {$px, $py} = $p; // Plain and simple. Perfectly straightforward.   {$vx, $vy} = $v;   return new Point($px + $vx, $py + $vy); } I've also heard a consideration about "Foo::Bar & { $var }" being ambiguous with respect to "is Foo::Bar now a const or an ADT class". This may be resolved in the VM. I don't consider this a major issue, and is simply something which can be disambiguated at optimizer-time or run-time, depending on what type of symbol it is. ---- I'm deeply unsatisfied by the handling of object properties: "Note that matching against a property's value implies reading that property's value", "If the property is uninitialized, an error will be thrown." and "If the property is undefined and none of the above apply, it will evaluate to null and a Warning will be issued." This is wildly inconsistent with arrays: "Of particular note, the pattern matching approach automatically handles array_key_exists() checking. That means a missing array element will not trigger a warning, whereas with a traditional if ($foo['bar'] === 'baz') approach missing values must be accounted for by the developer manually." Sure, a pattern match will read an objects property. Just like it reads an arrays entry. I assume the goal is "let's warn when an object property is typoed". But it just makes for two tiers. arrays get key_exists(), properties do not get property_exists(). I welcome surprises. From my point of view, pattern matching is an "is" operation. Thus it ought expressing isset-like semantics. I.e. the approach for arrays is correct, and should be mirrored to objects. I definitely think the approach of "let's warn about typos" is laudable, but consistency is important. It also means that uninitialized properties forcibly throw. It also has subtle ordering implications on the semantics, given that the implementation internally short-circuits. E.g. (assuming something like "class ResponseOrError { string $type; Exception $e; string $response; }"): if ($obj is ResponseOrError { type: "error", exception: $e }) { throw $e; } does not throw if $exception is uninitialized. and $type is not error. But $obj is ResponseOrError { exception: $e, type: "error" } will certainly throw. It further means that there needs to be some internal checked and you cannot simply write: if ($obj is ResponseOrError { exception: $e }) { throw $e; } This is bad design and takes a lot of flexibility, just for being typo-safe. There are better approaches towards typo-safety, e.g. in future (PHP 9) we could change isset() and all other similar checks (coalesce and this proposal) to immediately throw when a property is checked for existence, whose name does not exist on a class which is not marked #[\AllowDynamicProperties]. We should make use of that instead of shoe-horning this into this proposal. ---- Open questions: - match() "is" placement: I prefer match() is {}  rather than an "is" inside the construct. Simpler to me, but I think either choice is fine. - Positional array enforcement: It's relatively simple to intentionally get positional arrays via array_values(). I also don't think it's unexpected. That's just how PHP's arrays work. Enforcing positional arrays however will be quite surprising if e.g. an entry was removed: $a = [1, 2, 3]; unset($a[1]); if ($a is [1, 3]) {    // huh? It's [1, 2 => 3], not [1, 3]. } Thanks, Bob --------------EA0eJDUXohJ09za01rsTco6X Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit

Hey Larry,

On 1.12.2025 22:36:21, Larry Garfield wrote:
Hi folks.  Ilija and I would like to present our latest RFC endeavor, pattern matching:

https://wiki.php.net/rfc/pattern-matching

You may note the date on the RFC is from 2020.  Yes, we really have had this one in-progress for 5 years. :-)  (Though it was inactive for many of those years, in fairness.)  Pattern matching was intended as the next follow up to Enums, as it's a stepping stone toward full ADT support.  However, we also feel it has enormous benefit on its own for simplifying complex comparisons.

This RFC has been through numerous iterations, including a full implementation rewrite just recently that made a number of features much easier.  We have therefore included two patterns that were previously slated for later inclusion but turned out to be trivially easy in the new approach.  (Variable pinning and numeric comparison.)

Nonetheless, there are two outstanding questions on which we are looking for feedback.

Naturally given the timing, we will not be calling a vote until at least late January, regardless of how the discussion goes.  So, plenty of time to express your support. :-)


Thanks for bringing pattern matching up for discussion again.

----


I'd like to note that the class-access is very ugly.

// Shorthand
if ($p is Point(:$z, x: 3, :$y)) {
    print "x is 3 and y is $y and z is $z.";
}

The RFC gives as reasoning that the colon prefix is needed for support of positional parameters in ADTs. Sure. That's fine to anticipate these.

But what's not fine is using an inconsistent syntax for variable bindings across different contexts. In arrays binding is just a bare variable. In objects it suddenly needs a colon? What.

Also, a colon is very prone to being missed in the future with ADTs. Point::2D($y, $x) vs Point::2D(:$y, :$x). Means something completely different, but if you mess up just having the colon there or not, is a serious problem.

Can we instead find some solution, which satisfies both and still delivers consistency?


An earlier iteration of the RFC had the following very nice construction:

$p is Point&{ $z, x: 3, $y }

This just worked. It's a Point class, and then it matches the properties of the object. Nice.


This also works for future ADTs. Move::Forward&{ $amount }. Then, if there's a desire to actually *positionally* match an object. Then it's logical to use a parenthesized expression, for a tuple. I.e.:

$move is Move::Forward($a)

Where $a is assigned the first value passed to Move::Forward.


Similarly for destructuring without class name no longer works:

$json = json_decode($myInput);
if ($json is stdClass(type: "store", :$value)) {
   // why do I need to know/specify that it's a stdclass?! I'm just interested in the properties.
}

vs.

if ($json is { type: "store", $value }) {
   // 
}


This satisfies the requirements of keep the language clear and intuitive:
- Any standalone variable is bound. No weird colon shenanigans. The syntax is consistent.
- Positional binding is quite intuitively using parenthesis - you construct the enum with Foo::Bar($var) and you read it back on the right hand side with Foo::Bar($var).
- It naturally allows destructuring without class name.
- It makes it hard to accidentally write something totally different to what was meant.

(Also, it's likely more intuitive to users from other languages, like rust, which also has {} for named stuff and () for positional stuff.)


Further this particular syntax works nicely with a future scope of object destructuring, akin to array destructuring. As an example:

function addVec(Point $p, Vec $v) {
  Point(:$px, :$py) = $p; // I already know this is a Point, why do I need to repeat it. It also looks ugly and quite a bit like a left-hand function call. Like... assigning something to a returned reference?
  // Or would you do {$px, $py} for object destructuring? Well that's now truly inconsistent.
  Vec(:$vx, :$vy) = $v;
  return new Point($px + $vx, $py + $vy);
}

vs.

function addVec(Point $p, Vec $v) {
  {$px, $py} = $p; // Plain and simple. Perfectly straightforward.
  {$vx, $vy} = $v;
  return new Point($px + $vx, $py + $vy);
}


I've also heard a consideration about "Foo::Bar & { $var }" being ambiguous with respect to "is Foo::Bar now a const or an ADT class". This may be resolved in the VM. I don't consider this a major issue, and is simply something which can be disambiguated at optimizer-time or run-time, depending on what type of symbol it is.


----


I'm deeply unsatisfied by the handling of object properties:

"Note that matching against a property's value implies reading that property's value", "If the property is uninitialized, an error will be thrown." and "If the property is undefined and none of the above apply, it will evaluate to null and a Warning will be issued."

This is wildly inconsistent with arrays:

"Of particular note, the pattern matching approach automatically handles array_key_exists() checking. That means a missing array element will not trigger a warning, whereas with a traditional if ($foo['bar'] === 'baz') approach missing values must be accounted for by the developer manually."


Sure, a pattern match will read an objects property. Just like it reads an arrays entry.
I assume the goal is "let's warn when an object property is typoed". But it just makes for two tiers. arrays get key_exists(), properties do not get property_exists(). I welcome surprises.

From my point of view, pattern matching is an "is" operation. Thus it ought expressing isset-like semantics. I.e. the approach for arrays is correct, and should be mirrored to objects.

I definitely think the approach of "let's warn about typos" is laudable, but consistency is important.

It also means that uninitialized properties forcibly throw. It also has subtle ordering implications on the semantics, given that the implementation internally short-circuits. E.g. (assuming something like "class ResponseOrError { string $type; Exception $e; string $response; }"):

if ($obj is ResponseOrError { type: "error", exception: $e }) { throw $e; }

does not throw if $exception is uninitialized. and $type is not error. But $obj is ResponseOrError { exception: $e, type: "error" } will certainly throw.

It further means that there needs to be some internal checked and you cannot simply write:

if ($obj is ResponseOrError { exception: $e }) { throw $e; }


This is bad design and takes a lot of flexibility, just for being typo-safe.

There are better approaches towards typo-safety, e.g. in future (PHP 9) we could change isset() and all other similar checks (coalesce and this proposal) to immediately throw when a property is checked for existence, whose name does not exist on a class which is not marked #[\AllowDynamicProperties].
We should make use of that instead of shoe-horning this into this proposal.


----


Open questions:

- match() "is" placement:
I prefer match() is {}  rather than an "is" inside the construct. Simpler to me, but I think either choice is fine.

- Positional array enforcement:
It's relatively simple to intentionally get positional arrays via array_values(). I also don't think it's unexpected. That's just how PHP's arrays work. Enforcing positional arrays however will be quite surprising if e.g. an entry was removed:

$a = [1, 2, 3];
unset($a[1]);
if ($a is [1, 3]) {
   // huh? It's [1, 2 => 3], not [1, 3].
}


Thanks,

Bob

--------------EA0eJDUXohJ09za01rsTco6X--