Oh, here's a thought: let's just throw more annotations at it?

$config = /** @ref AppConfiguration */ array(
    'services' => /** @ref ServiceContainer */ array(
        /** @ref PDO */ array(
            'username' => 'foo',
            'password' => 'bar',
        )
    ),
);


This would work - it would instruct a static analyzer that the keys in
those arrays are actually references to properties, and you could then
autocomplete the strings and property-names, display inline documentation,
perform inspections, etc.

The same would work in form-helpers:

echo $form->textInput(/** @ref User */ 'email');


Auto-complete, auto-refactoring, all possible now.

It looks horrible of course, and pretty soon we'll be extending our
annotation-parsers to get access to the static information embedded in
doc-blocks that isn't part of the language.

It's not very elegant, because it addresses a problem, but ignores the
underlying root of the problem. It treats a symptom, not the cause. (the
staple of American over-priced inferior health care, or perhaps more
accurately, "sick care".)

I really like to see programming languages addressing problems at the root.
We should look below every need and every problem to find the simplest
possible solution that best addresses the broadest possible set of problems.

Maybe this feature doesn't do that. But then let's ponder what does?

There has got to be ways in which the language can better facilitate things
like property indirection and other needs for more static features?

And I don't believe that will ruin the experience or bump the learning
curve for an otherwise very accessible language - seeing as how everyone
has to learn how to decorate their code with static information sooner or
later.

PHP is being used for much bigger things these days than just forums and
blogs - it's driving big applications and services.

You don't think it's possible to elevate the language to a level where it
can facilitate complex architecture as well as simple forums and blogs?

You've made strides these past few years, you really have. Please don't
quit or think you're all done? :-)


On Thu, May 2, 2013 at 10:33 AM, Rasmus Schultz <ras...@mindplay.dk> wrote:

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