Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:58452 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 82197 invoked from network); 2 Mar 2012 03:48:48 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 2 Mar 2012 03:48:48 -0000 Authentication-Results: pb1.pair.com header.from=ircmaxell@gmail.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=ircmaxell@gmail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.212.170 as permitted sender) X-PHP-List-Original-Sender: ircmaxell@gmail.com X-Host-Fingerprint: 209.85.212.170 mail-wi0-f170.google.com Received: from [209.85.212.170] ([209.85.212.170:51546] helo=mail-wi0-f170.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 94/01-11220-E13405F4 for ; Thu, 01 Mar 2012 22:48:47 -0500 Received: by wibhj13 with SMTP id hj13so463701wib.29 for ; Thu, 01 Mar 2012 19:48:44 -0800 (PST) Received-SPF: pass (google.com: domain of ircmaxell@gmail.com designates 10.180.99.100 as permitted sender) client-ip=10.180.99.100; Authentication-Results: mr.google.com; spf=pass (google.com: domain of ircmaxell@gmail.com designates 10.180.99.100 as permitted sender) smtp.mail=ircmaxell@gmail.com; dkim=pass header.i=ircmaxell@gmail.com Received: from mr.google.com ([10.180.99.100]) by 10.180.99.100 with SMTP id ep4mr1211343wib.7.1330660124009 (num_hops = 1); Thu, 01 Mar 2012 19:48:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=pTMZ4XtZpZzj+sRrBxVY0OgA9sXoaNu6NudbcNbbsgo=; b=LccG2p64j4X+1oLHomme5thBSZ1mb+MfiV8a4VZnKHTdNGKpwhYq4d6kkByi3lL7M6 AAn0tDMNVe+78HBtrOyxB4x4gH26d6Jp8TzroG/R+5bfKpzXqIjo38uOtaChZChgYTIa EaSXNaWnui0qZK3qeeLKVbSQ0bvmpJ5jkKSl5m8uITPMzIedIVuullDnrNgYeEpKfsMI 9ZozMOFs3cvaUQlS2uLXY7UYC7yzM8jWJayBZSQpBoGCoNGESWxaedmu5ve8OPCEgeY8 dkz+bCKxMaNwv/FftY3nmNOH6W8LXErMfDdwGB0CRm3Pk+deKFjHsBlKpUvnM1FU2qFB kVPA== MIME-Version: 1.0 Received: by 10.180.99.100 with SMTP id ep4mr981994wib.7.1330660123942; Thu, 01 Mar 2012 19:48:43 -0800 (PST) Received: by 10.216.137.20 with HTTP; Thu, 1 Mar 2012 19:48:43 -0800 (PST) Date: Thu, 1 Mar 2012 22:48:43 -0500 Message-ID: To: internals@lists.php.net Content-Type: text/plain; charset=ISO-8859-1 Subject: [POC Patch] Scalar Type Hinting/Casting - Proof Of Concept From: ircmaxell@gmail.com (Anthony Ferrara) Hey all, I know given all the discussion about this topic lately, this is a hot topic. But I whipped together a quick POC patch to implement scalar type casting for function parameters. Let me describe it: Patch: https://gist.github.com/1947259 Example: function foo( (int) $bar ) { var_dump($bar); } foo(1); // int(1) foo("1"); // int(1) foo(1.5); // int(1) foo("foo"); // E_RECOVERABLE_ERROR - Expected integer foo(array()); // E_RECOVERABLE_ERROR Right now, I only implemented the checks for (int), but I add the parser constructs for (int), (float), (bool), (string) and (object)... Now, let's talk why I did what I did: Why did I use cast syntax? Well, there are really three main reasons. First off, to indicate that a cast may happen. Second, to prevent needing new tokens (and hence reserved words). And third to provide a distinction between a string class type hint and a string scalar type hint. Why did I only implement (int)? Well, because I just wanted to build a quick dirty POC that can be executed to see the semantics of operation. There are issues with it now, so rather than doing all the work to re-do it later, I just implemented int... Why implement (object)? Because right now, there's no way to say you want to accept a generic object without caring about type. So the (object) cast/hint would then provide that ability to accept a generic object. Why not implement (resource)? Because that would require a new parser token, as it's not available now... How does the casting work? Right now, it's using a copy of the same rules that internal functions use with zend_parse_parameters. That way, it brings the operating semantics of internal functions and userland functions more inline with each other. So with that said, there are some (significant) issues with the patch: 1. First off, the arg checks happen before separation of the zval on non-referenced calls. So that means the cast effects the original zval AND the argument. Which is a no-go for a production patch. So that means that the cast logic would need to be put after the zval split. But we'd still want the checks first, so it's not too difficult to segregate, just requires deeper changes. It's not difficult (that I can see yet), just more work... Example of the problem: # sapi/cli/php -r 'function foo((int) $bar) { var_dump($bar); } $a = "1"; foo($a); var_dump($a);' int(1) int(1) 2. Right now, the zend_aprse_arg_impl ( http://lxr.php.net/xref/PHP_5_4/Zend/zend_API.c#zend_parse_arg_impl ) that's used by internal functions is defined as static. So we'd be copying a lot of the code back and forth. In the production patch, I'd also want to re-factor that out a bit into either functions or macros to handle the type conversion and casting in both places. That way, both systems would behave identical (or as close as possible). So, with that said, what do you think? Is this something worth pursuing? Are there any fundamental issues that I'm missing? What else would we need to cover in a production patch and RFC? Thanks, Anthony