>
> "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
>

Reply via email to