Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:101477 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 45194 invoked from network); 2 Jan 2018 10:35:38 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 2 Jan 2018 10:35:38 -0000 Authentication-Results: pb1.pair.com smtp.mail=tendoaki@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=tendoaki@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.213.172 as permitted sender) X-PHP-List-Original-Sender: tendoaki@gmail.com X-Host-Fingerprint: 209.85.213.172 mail-yb0-f172.google.com Received: from [209.85.213.172] ([209.85.213.172:39991] helo=mail-yb0-f172.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 24/A2-23177-A706B4A5 for ; Tue, 02 Jan 2018 05:35:38 -0500 Received: by mail-yb0-f172.google.com with SMTP id s10so3567342ybl.7 for ; Tue, 02 Jan 2018 02:35:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=f1JrfJzLzSXR5o38o7AE9O8fMQrl08yBiX9F6VJ6gxw=; b=pwlWugZvaS8hDLjBXWbKuGX0cxuMi5zNSGEtI2Vl4cOVQ47R4/G/lAqmZo2NyF1w8x tE0IcZQk+S8XHZ5z+RXwEcAasSHkQ+2zcWhZ94r/sRpxB3MppjcnWXOdNIiWOg0TBuK7 r+ssq6NuRrHCQrO7hDV+iHbuDb5P1AHgQBrosowYfMpzZB2pp/3VpC76BxBOzo1mG8fe l/nXnoiraZh5h2Se/WWAT3pXzBJl6oi/vC9669iwrHqp2oM6Wl4HaC/bBaFlkHv6EeJu oA1COZ/FG48j9XUER0wvq1oFDQSZf3PJD63yJGWpJPaIig3SO9i9VS0CxTlkeW6amhYr HAfw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=f1JrfJzLzSXR5o38o7AE9O8fMQrl08yBiX9F6VJ6gxw=; b=rHiF+RrhxRzhPXaQolFJJ93rn3PrN1aHilLFV6Ro52PiGM8reIR6igKEzRCHPILWpp OOVQtVbJeGgnRFF9PSDawYAqgdMFzaBcFGNNpczqViHnOuJ/oFAgccdTU9kpBnSZBEW1 ZR9q0XTs48khXDAb94ivIO2ZwI+3eaWCZDDuV5ONkDtN0igP9eYNtv5FgJ9OloTbK0xY J/UZoMTfL8Xc5Uy9svZyH9Im+Nue8vs5SmgI+zjbANsThL9a9Pb9tUsuoRSu4CJHZeXe Aco5n7fB0lUhDWb5Z94BK36r0mVeLbq9soO6mDgURZa21IpE2DL4f6xR/NLM10e5icOP APXQ== X-Gm-Message-State: AKGB3mL1thi3HggYk0FiarKPad+bGMkzVXavdk5ZprB6M0N9CU38q7x6 II7qAphfMaIf7vneO6uBw741GgA/vc5+Xi09hzoa1A== X-Google-Smtp-Source: ACJfBotXgr9O2cVSAUL/ApJK/kqW6cPWFJ2ujw+N5BjQ1X+/jCml+jOqvLVNB3K0SOKqMVxpz2+2quo1shIhF1e3A0U= X-Received: by 10.37.94.85 with SMTP id s82mr19745905ybb.131.1514889335697; Tue, 02 Jan 2018 02:35:35 -0800 (PST) MIME-Version: 1.0 Received: by 10.37.201.7 with HTTP; Tue, 2 Jan 2018 02:35:35 -0800 (PST) Date: Tue, 2 Jan 2018 05:35:35 -0500 Message-ID: To: PHP internals Content-Type: multipart/alternative; boundary="001a11425b90ba77ab0561c8a8b5" Subject: [RFC][DISCUSSION] Strong Typing Syntax From: tendoaki@gmail.com (Michael Morris) --001a11425b90ba77ab0561c8a8b5 Content-Type: text/plain; charset="UTF-8" I would like to propose a clean way to add some strong typing to PHP in a manner that is almost fully backward compatible (there is a behavior change with PHP 7 type declarations). As I don't have access to the add RFC's to the wiki I'll place this here. Before I begin detailing this I want to emphasize this syntax is optional and lives alongside PHP's default scalar variables. If variables aren't declared using the syntax detailed below than nothing changes. This is not only for backwards compatibility, but it's also to keep the language easy to learn as understanding datatypes can be a stumbling block (I know it was for me at least). VARIABLE DECLARATION Currently the var keyword is used to formally declare a variable. The keyword will now allow a type argument before the var name as so var [type] $varname; If the type is omitted, scalar is assumed. If Fleshgrinder's scalar RFC is accepted then it would make sense to allow programmers to explicitly declare the variable as a scalar, but in any event when the type is omitted scalar must be assumed for backwards compatibility. The variables created by this pattern auto cast anything assigned to them without pitching an error. So... var string $a = 5.3; The float of 5.3 will be cast as a string. For some this doesn't go far enough - they'd rather have a TypeError thrown when the assignment isn't going to work. For them there is this syntax string $a = "Hello"; Note that the var keyword isn't used. FUNCTION DECLARATION PHP 7 introduced type declarations. This RFC calls for these to become binding for consistency, which introduces the only backward compatibility break of the proposal. Consider the following code. function foo ( string $a ) { $a = 5; echo is_int($a) ? 'Yes' : 'No'; } Under this RFC "No" is returned because 5 is cast to a string when assigned to $a. Currently "Yes" would be returned since a scalar has the type that makes sense for the last assignment. I believe this is an acceptable break for two reasons. 1, the type declaration syntax is relatively new. 2, changing the type of a variable mid-function is a bad pattern anyway. OBJECT TYPE LOCKING Currently there is no way to prevent a variable from being changed from an object to something else. Example. $a = new SomeClass(); $a = 5; If objects are allowed to follow the same pattern outlined above though this problem is mostly solved.. SomeClass $a = new SomeClass(); var SomeClass $a = new SomeClass(); QUESTION: How do we handle the second auto casting case? $a is not allowed to not be a SomeClass() object, but there are no casting rules. We have three options: 1. Throw an error on illegal assign. 2. Allow a magic __cast function that will cast any assignment to the object. 3. Create a PHP Internal interface the object can implement that will accomplish what 2 does without the magic approach. Note that 1 will need to occur without implementation. 2 and 3 are not mutually exclusive though my understanding is PHP is moving away from magic functions. CLASS DECLARATION Again, by default class members are scalars. The syntax translates over here as might be expected. class SomeClass { public var string $a; protected int $b; private SomeOtherClass $c; public var SomeThirdClass $d; } Note a default value doesn't need to be provided. In the case of object members, these types are only checked for on assignment to prevent recursion sending the autoloader into an infinite loop. Also note that one of the functions of setters - guaranteeing correct type assignment - comes free of charge with this change. COMPARISON BEHAVIOR When a strongly typed variable (autocasting or not) is compared to a scalar variable only the scalar switches types. The strict comparison operator is allowed though it only blocks the movement of the scalar. Comparisons between strongly typed variables are always strict and a TypeError results if their types don't match. This actually provides a way to force the greater than, lesser than, and spaceship operation to be strict. FUNCTION CALLING When a strong typed variable is passed to a function that declares a variable's type then autocasting will occur so long as the pass is not by reference. For obvious reasons a TypeError will occur on a by reference assignment.. function bar( string $a) {} function foo( string &$a ) {} $a = 5.3; foo( $a ); // Works, $a is a scalar, so it type adjusts. var bool $b = false; foo( $b ); // TypeError, $b is boolean, function expects to receive a string by reference. bar($b); // Works since the pass isn't by reference, so the type can be adjusted for the local scope. CONCLUSION I believe that covers all the bases needed. This will give those who want things to use strong typing better tools, and those who don't can be free to ignore them. --001a11425b90ba77ab0561c8a8b5--