> > "authors[0].personalDetails[firstName]" > > >> which translates to > > >> ->getAuthors()[0]->getPersonalDetails()['firstName'] > > It's indirection via strings.
This particular example isn't great for what I'm proposing, because you're not accessing a property - using an array-index, you get a value. There is no property - hence nothing to reflect on. Assuming you have accessors for those get() and set() methods, and assuming $firstName is an object-property and not just a hashed string, why not simply: $p = ^$authors[0]->personalDetails->firstName; Assuming you added static information about the type of $authors, what was previously a string (for which you need a run-time parser and a bunch of code) is now IDE-friendly, with auto-completion as you type, inspections, accurate refactoring, etc. (without writing framework-specific plug-ins for every major IDE.) If $authors is an array, this might translate roughly into: $p = new PropertyReference($authors[0]->personalDetails, 'firstName'); Or perhaps with more lazy evaluation: $p = new PropertyReference( function () use (&$authors) { return $authors[0]->personalDetails; } , 'firstName' ); It's still dynamic, but the source-code now contains more static information - you're using PHP syntax instead of inventing custom syntax and parsing it out of strings, for things the language can already do, but doesn't do elegantly. You now have the ability to reflect on the type of the $personalDetails object and the $firstName property and establish defaults based on annotation parsing (as as popular in Symfony) or conventions for labels ('firstName' => 'First Name') etc. You can assert early on if this code is going to work. You can know if you making a break change somewhere along that object graph. You don't need a library to parse custom syntax for value paths at run-time anymore, you're not inventing new syntax for something the language can already do, and developers no longer need to learn that custom syntax. You can use automated refactoring. Your IDE can provide auto-complete and inline documentation as you type. I don't like strings for references to source-code elements. It's ugly, it's unsafe, it can't be analyzed or refactored, and it's bloody backwards - to use a different example, look at this oddly popular approach to configuration: $config = array( 'foo' => 'bar', 'services' => array( 'db' => array( 'username' => '...', 'password' => '...', ), 'email' => array( 'host' => '....', ), ), ); Those are not objects and properties, they are arrays and strings, and they are dead matter. But they map 1:1 to objects and properties. So for all intents and purposes, they are a dead form of objects and properties that can only be revived at run-time - nothing can be known about the existence of any of those objects or properties prior to actually running the code. That means you can expect some ugly surprises down the line, when one of these unchecked references turn out to be wrong, or some change/refactoring breaks code that worked before. Or you can spend a lot of time writing unit-tests for things that shouldn't be able to fail in the first place. There are ways around that, and it involves relying on the static qualities of the language: $config[] = function (PDO $db) { $db->username = 'foo'; $db->password = 'bar'; }; Thanks to the type-hint - a popular static language feature - this code can inspected and checked. If you wanted the same for your nested arrays and strings, you would have to write plug-ins for every major IDE - more code. I like simple things. That's one of the key reasons I like PHP. Dynamic is not automatically simpler. Especially not when you have to learn and write and maintain oodles of static source-code annotations to bring the code-quality up to a level that is accepted by the PHP community at large. If you think keeping the language simple makes life simpler, you're fooling yourself. It's good that people like Bernhard have the time and energy to come up with solutions to problems like these - it's bad when we have to resort to unchecked code and custom syntax and parsers and IDE plug-ins to solve these problems and work comfortably with those solutions. Exclusively static languages aren't the answer, but neither are dominantly dynamic languages - the majority of PHP code is heavily embedded with static information for a reason. I would never want to see the dynamic features of the language crippled or encumbered in favor of static features - but to ignore the need for more static features in the language is to hold back a natural development that is already happening whether you approve of it or not. Maybe this particular feature is wrong for other reasons, I don't know, that's why we're discussing it. But don't reject the idea because it's static and doesn't fit with your ideas of a dynamic language. On Thu, May 2, 2013 at 9:06 AM, Bernhard Schussek <bschus...@gmail.com>wrote: > 2013/5/1 Rasmus Schultz <ras...@mindplay.dk> > >> > One could >> > write a PropertyReference class right now with literally the only >> > difference being the lack of a builtin operator (ie new >> > PropertyReference($obj, 'prop') versus ^$obj->prop): the fact that >> > nobody seems to have done this in a major framework I know of suggests >> > that there isn't a strong need for encapsulating the indirection >> > beyond the $obj->$prop syntax that's worked forever. >> > >> >> Look at the Symfony form-builder example - encapsulating the indirection >> is >> *precisely* what they're doing: the object reference is stored in the >> form-builder, and property-names are added subsequently. >> > > As the developer of the Symfony Form component, I would like to clarify > that this is not true. At the time the property reference is stored, the > object it refers to is not (necessarily) known. You could build an abstract > form definition for "Author" instances, but only later instantiate a form > for that definition with a concrete object. So to be really useful in a > form context, property references need to be separated from object > instances (something like "^Author::$firstName" could work). > > Second, it is important that references can span multiple nodes in an > object/array graph. In Symfony, we built the PropertyAccess component for > that [1] which allows references like > > "authors[0].personalDetails[firstName]" > > which translates to > > ->getAuthors()[0]->getPersonalDetails()['firstName'] > > or > > ->authors[0]->getPersonalDetails()['firstName'] > > etc., depending on whether accessors exist or the properties themselves > are public (also works for writing values). This is a concept borrowed from > Java and known as "property paths". [2] Without the possibility of > chaining, property references are useless IMO. > > Cheers, > Bernhard > > [1] > http://symfony.com/doc/current/components/property_access/introduction.html > [2] > http://static.springsource.org/spring-data/data-commons/docs/1.3.0.M1/api/org/springframework/data/mapping/PropertyPath.html >