Re: [PHP-DEV] making system calls from a php extension

2011-05-11 Thread Ben Schmidt

On 11/05/11 2:33 PM, Rasmus Lerdorf wrote:

On May 10, 2011, at 21:01, Gabriel Sosasosagabr...@gmail.com  wrote:

I'm basically using lynx to convert some html into plain text

basically replicating the following command:

*lynx -pseudo_inlines=off -hiddenlinks=merge -reload -cache=0 -notitle
-force_html -dump -nocolor -stdin*

I've been looking but I didn't find any other library capable to do
the same with almost the same quality.


You may be right that it does it better than other mechanisms and it
may be the way to go. But it sounds like you need it to be faster. You
are still not going to gain much simply by calling lynx from C. The
only way to speed this up is to not have to fork and exec a new
process on every request. One way to do that would be to figure out
how to talk to an already running instance of lynx. Then write a
little Gearman wrapper for them and launch a bunch of Gearman workers.
Another benefit of this approach is that you will be able call lynx
asynchronously.


Rasmus is spot on, but another thought is that if your content is often
the same, caching it somehow (either with PHP code or with a PHP
extension--I would just try PHP code for starters) could yield large
speed-ups, too.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Making SimpleXML more useful

2011-04-30 Thread Ben Schmidt

Again, xmlns= puts an element in no namespace. That already works in
SimpleXML. There is no issue here that needs fixing.


IIUC, the OP doesn't want the element to be in no namespace, but wants
it to be in the default namespace, but unprefixed.

I have already laid out my reasons for believing requiring this in a
schema, although perhaps formally possible, goes against the XMLNames
spec. I won't repeat those reasons here. Suffice it to say that I don't
think anything needs fixing either.

However, there is something you cannot currently do with SimpleXML, and
that is add an unprefixed element that falls in the default namespace.
And although I don't think it's a bug that needs fixing, it wouldn't
hurt to add that functionality with something like:

$r-addChild(child,null,SIMPLEXML_DEFAULT_UNPREFIXED);

This adds a certain ambiguity to document creation if it is used, but it
does add functionality not currently there. I guess it's only worth
doing if there are specs out there in the wild that (wrongly IMHO)
require unqualified names in XMLNames-conforming documents.

So, if the OP or his associates are in control of his schema, I suggest
he should change it; if he can point to a respectable public schema that
does this, it would be worthy of greater consideration.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Making SimpleXML more useful

2011-04-29 Thread Ben Schmidt

While I think this would make SimpleXML more stupid, not less, as it
seems braindead to me to allow users to create documents ambiguously
and/or which essentially violate the XML namespace spec, I think the
way to do


Allowing child elements to be unqualified is neither braindead or
ambiguous.  All standalone XML documents are ambiguous, because XML is
just structured information without a definition of the structure (let
alone the semantics of the information).  XMLSchemas precisely define
the structure, including allowable elements, child elements,
quantities of elements and data types.  And if that schema includes
the attribute 'elementFormDefault=unqualified', then child elements
have to be unqualified.  And that is certainly strictly specified,
unlike a schemaless XML.


Let me clarify. I didn't mean that the document would be ambiguous, I
mean that the means of creating it could be. E.g. take my preferred
syntax, and consider these code snippets:

$root = new SimpleXMLElement(
   'ns1:r xmlns=urn:ns1 xmlns:ns1=urn:ns1 /'
);
$root-addChild(child,null,SIMPLEXML_DEFAULT_UNPREFIXED);
echo $root-asXML();
// Gives: ns1:r xmlns=urn:ns1 xmlns:ns1=urn:ns1child //ns1:r

$root = new SimpleXMLElement(
   'ns1:r xmlns:ns1=urn:ns1 /'
);
$root-addChild(child,null,SIMPLEXML_DEFAULT_UNPREFIXED);
echo $root-asXML();
// Gives: ns1:r xmlns:ns1=urn:ns1child //ns1:r

In the first case, the child is in urn:ns1, in the second case, it is
not. So, at the time of the addChild() call, you don't actually know
what namespace your element will end up in.

And if you *want* that distinction not to matter, it is a violation of
the XML namespace spec, which says that conforming documents must be
interpreted according to namespace defaulting rules, element names must
always be considered qualified, etc..

So, either there is ambiguity while you are creating the document, or
there is violation of the spec.


this would be to
define a magic constant and use that. E.g.

const SIMPLEXML_DEFAULT_UNPREFIXED = 0

I used 'default unprefixed' to better describe what is going to
happen in terms of namespaces (as within the context of a namespaced
document is the only time this would be needed): the element is going
to be created in the default namespace by virtue of being unprefixed.
This highlights to the user the ambiguity involved (it is not
necessarily known what the default namespace is at any point), as
well as the 'priority' the XML generation will take at that point (of
adding an unprefixed element).



-1 for using unqualified; whatever is used should not be a possibly
valid namespace name.


Well, it is possible to examine the type, so (int) -1 is distinct
from -1, so there is no risk of considering it an actual
namespace.  So, like this:

$sxe-addChild('child', 123);  # Adds element with namespace inherited from the 
parent
$sxe-addChild('child', 123, 'urn:somenamespace'); # Adds child with specified 
namespace
$sxe-addChild('child', 123, -1);  # Adds child with no namespace qualification


Sorry; I was unclear (again). By '-1 for using unqualified' I meant 'a
vote against using unqualified'.

I don't think you should just use an int, but should provide a constant
that evaluates to it, so more readable code can be written:

$sxe-addChild('child', 123, SIMPLEXML_DEFAULT_UNPREFIXED);

instead of

$sxe-addChild('child', 123, -1);

I think using 0 or 1 would be better than -1, i.e. make it like an enum
or a bitmask so it can be extended in future if ever necessary
(unlikely, but best to be prepared!).


That wouldn't be hard to do.  But I don't really want to create a patch, unless 
someone will accept it.


I'd be happy with the above as long as you add a constant, but like you,
I am a mere mortal so have no power to approve/reject/commit/etc..

I believe Rob Richards, who wrote back briefly before, is the right man
to give approval to this (CCing him directly).

I'll butt out now, I think.

Cheers,

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Return type-hint

2011-04-28 Thread Ben Schmidt
FWIW, I don't see much point in this either, as far as error reporting is 
concerned. I think type checking for parameters can provide cheap and useful 
validation, as parameters passed in are outside the function's control. But return 
values? They are within the function's control, and in most functions are not hard 
to ensure are correct without needing runtime checking.


If PHP were compiled, not interpreted, i.e. less dynamic, there could be some 
benefits, as compile-time optimisations could perhaps be built in, and validations 
skipped if they were provably unnecessary. But that's not going to happen any time 
soon, as far as I'm aware.


So the only real benefit is that they could make code slightly self-documenting. 
But since they would still be optional, they don't help much: the coder might as 
well take up the option to write some more useful documentation.


Also, PHP has so many conventions such as returning false on error that don't fit 
cleanly into the model, that it's awkward. I'd love to see those problems solved 
neatly for function arguments before extending anything to function return types.


I don't think it would do any harm though, so don't see any argument against it. I 
just don't think there's a good argument for it.


Ben.



On 28/04/11 6:23 PM, Stas Malyshev wrote:

Hi!


http://wiki.php.net/rfc/returntypehint

for the upcoming 5.4 release, I think it would be extremely useful, even
without the scalar stuff.



Personally, I see even less point in having strict return typing (please stop
using hint terminology, it confuses the whole matter, it's not hint if it
describes mandatory restriction on the data) than strict argument typing. The 
RFC
doesn't explain it either beyond here how you can have some nice errors.
But why would I want to see these errors? How they would make anything easier or
better?


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Return type-hint

2011-04-28 Thread Ben Schmidt

On 29/04/11 2:10 AM, Alain Williams wrote:

On Fri, Apr 29, 2011 at 01:58:02AM +1000, Ben Schmidt wrote:


If PHP were compiled, not interpreted, i.e. less dynamic, there could be
some benefits, as compile-time optimisations could perhaps be built in, and
validations skipped if they were provably unnecessary. But that's not going
to happen any time soon, as far as I'm aware.


It has already happened:

https://github.com/facebook/hiphop-php/wiki/

It might also be useful for reflection.


*Hastily retracts comment.*

That is very cool. I should give it a try.

I also see the value of such type checking for such a use case, obviously.

I guess there's a reason for it after all.

I'd still like to see something neat to handle more than just named classes, 
though, e.g. scalars, and things like false on error for return values.


Ben.



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Making SimpleXML more useful

2011-04-28 Thread Ben Schmidt
While I think this would make SimpleXML more stupid, not less, as it seems 
braindead to me to allow users to create documents ambiguously and/or which 
essentially violate the XML namespace spec, I think the way to do this would be to 
define a magic constant and use that. E.g.


const SIMPLEXML_DEFAULT_UNPREFIXED = 0

I used 'default unprefixed' to better describe what is going to happen in terms of 
namespaces (as within the context of a namespaced document is the only time this 
would be needed): the element is going to be created in the default namespace by 
virtue of being unprefixed. This highlights to the user the ambiguity involved (it 
is not necessarily known what the default namespace is at any point), as well as 
the 'priority' the XML generation will take at that point (of adding an unprefixed 
element).


-1 for using unqualified; whatever is used should not be a possibly valid 
namspace name.


Ben.



On 29/04/11 7:48 AM, Tom Samplonius wrote:




That patch is not a good idea.

Assume you have this situation:

foo xmlns=urn:lol
x:bar xmlns:x=urn:hai
/x:bar
/foo

Adding a child baz to bar and have it default to no namespace


Actually, my patch wouldn't change the default action of addChild(). It would 
still inherit the namespace qualification of the parent by default.


prefix would result in this:

foo xmlns=urn:lol
x:bar xmlns:x=urn:hai
baz /
/x:bar
/foo

Nowbaz /  would be in the namespace urn:lol.


I don't see why this is a problem? I actually need to be able to add 
unqualified child elements.


Keep in mind that xmlns= is, as per the XML spec, a perfectly valid
way to reset the namespace of an element.


Right now, the behavior of addChild() is:

* $namespace is unspecified --  inherit from parent
* $namespace is specified --  use that as the namespace for the element (and this could 
be )

I need a third option, where I can add an element that is unqualified. There really are just two 
possible choices, either add a new value of $namespace (like (int) 0) that requests 
this behavior. Or, use some sort of magic namespace value (like unqualified) to specify 
an unqualified element.

Is there any opinion on which is better for addChild()?

...

SimpleXML is supposed to be simple (I find it more stupid than simple, but 
that's my personal opinion).
I guess that's why it, by default, inherits the parent namespace


The only way to make it less stupid, is to start fixing it.


Tom



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Making SimpleXML more useful

2011-04-27 Thread Ben Schmidt

problem for me, as I have an XML schema that specifies that the
child elements must not namespace qualified.



Is this possible in an XML schema? I don't know much about schemas,
but

...

Absolutely, if the XML schema has the elementFormDefault attribute
set to unqualified, the child elements must be unqualified.


I'm not sure what this means. If any element name or attribute name that
is not a namespace declaration is not a qualified name, the document
does not conform to the XML namespaces specification.

From http://www.w3.org/TR/xml-names/#ns-qualnames :

In XML documents conforming to this specification, some names
(constructs corresponding to the nonterminal Name) MUST be given as
qualified names

And from http://www.w3.org/TR/xml-names/#ns-using :

In XML documents conforming to this specification, element names are
given as qualified names ... Attributes are either namespace
declarations or their names are given as qualified names

My guess would be that either:

- 'Unqualified' in this context doesn't actually mean 'unqualified
  name', but means 'not in a namespace'. In this case, to specify such
  an element in an XML document that uses namespaces, an unprefixed name
  must be used with no default namespace in scope.

- 'Unqualified' is not meant to be mixed with 'qualified' in the same
  document, and exists so that XML with elements/attribute names using
  colons can be used without a namespace-interpretation; this is not
  recommended, but legal, and parsers are required to be able parse such
  documents. If this is the case, things are beyond rescue, I think; the
  XML described by the schema does not conform to the XML namespace
  spec, and we can't expect SimpleXML to deal with it, certainly not in
  a namespace-aware way.


I would also expect, if the child were to be namespaced, that these
are equivalent:



ns1:parent xmlns=whatever xmlns:ns1=whatever
childabc/child
/ns1:parent



ns1:parent xmlns:ns1=whatever
ns1:childabc/ns1:child
/ns1:parent

...

In the first case, the child element is unqualified,


No, it is not. It is syntactically a qualified name, if the document
follows the XML namespace spec. But it is an unprefixed qualified name.
In this case, though, it is in the whatever namespace, due to scoping
rules.

From http://www.w3.org/TR/xml-names/#defaulting :

The scope of a default namespace declaration extends from the beginning
of the start-tag in which it appears to the end of the corresponding
end-tag,

So the xmlns=whatever is in effect for child. Furthermore:

A default namespace declaration applies to all unprefixed element names
within its scope. ... If there is a default namespace declaration in
scope, the expanded name corresponding to an unprefixed element name has
the URI of the default namespace as its namespace name.

So the namespace name of child is whatever.


and in the second, it is not.


Yes. It is both qualified and prefixed. Child very obviously is in the
whatever namespace.


They are not the same thing, either semantically or otherwise.


So they are semantically the same, at least in that child is in the
whatever namespace in both cases.


and the xmlns= is necessary. If this functionality were removed,
how could this be done?


For what?  In the spec (http://www.w3.org/TR/xml-names/#iri-use), it
says:

The empty string, though it is a legal URI reference, cannot be used
as a namespace name.


xmlns= does not mean elements are in a namespace with an empty name,
but that there is no default namespace.

From http://www.w3.org/TR/xml-names/#defaulting :

The attribute value in a default namespace declaration MAY be empty.
This has the same effect, within the scope of the declaration, of there
being no default namespace.

So these are equivalent:

ns1:parent xmlns=whatever xmlns:ns1=whatever
child xmlns=abc/child
/ns1:parent

ns1:parent xmlns:ns1=whatever
childabc/child
/ns1:parent

In both cases, child is not in a namespace. Perhaps this is what is
meant by 'unqualified' in the XML schema stuff.


Sure, SimpleXML could perhaps output XML that is slightly more
efficient/less verbose than it currently does, but its output is not
incorrect, and the functionality you want to remove is necessary in
other circumstances.


I don't see how removing the ability to use  as a namespace is an
issue, since  can't be used as a namespace name.


It removes the ability to add a non-namespaced element at a position in
a document where a default namespace is in effect. Specifying 
indicates a non-namespaced element should be added, and adding xmlns=
is the way SimpleXML ensures it is achieved, by ensuring it is as if no
default namespace is in effect.

Cheers,

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



[PHP-DEV] DVCS

2011-04-27 Thread Ben Schmidt

Hi!

I realise that at least for now, PHP is sticking with SVN. No problems.

However...I find it much easier to work in Mercurial to put together
patches, find bugs, etc.. And in fact, I find SVN really awkward--I was
on the verge of switching back to CVS when DVCSes such as Mercurial and
Git became popular. I would put in a vote for Mercurial if PHP decides
to move to a DVCS. Mercurial is more similar to CVS/SVN in its command
set than other DVCSes, is easy and friendly to use, generally does what
you would expect, makes it pretty hard to shoot yourself in the foot,
and includes good Windows support. Operating with the Mozilla and Vim
Mercurial repositories is a lovely experience, and I'd love to add PHP
to the list of projects I follow this way.

However, pushing the team towards a DVCS is not what I'm writing for.
Certainly not to push for a particular one.

I'd just like to be able to use my tool of choice (Mercurial) locally.
Would it be possible to set up a Mercurial mirror of the SVN repo on,
say, bitbucket.org, so I could pull from there? Alternatively, I can
access a git repo somewhere like github.com (I found
https://github.com/php/php-src but the last activity seems to be about 9
months ago--is it dead? are there any plans to revive it?). Of course,
as a last resort, I could just access SVN using Mercurial. However, it
may result in a lower server load if PHP can provide a mirror somewhere,
updated by a commit hook or daily cron job or something, rather than me
(and potentially many others, as DVCSes become even more popular)
accessing SVN directly.

Any possibility? (I'm happy to help, if I can be given appropriate
access to resources to do so.)

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] DVCS

2011-04-27 Thread Ben Schmidt

I think I agree with all that.

My only thought so far about the load issue is that the load is less the fewer 
changesets have to be queried each 'poll', so perhaps it would be good to have a 
commit hook in SVN that sends a quick request (without even waiting for a reply) 
to Hg/Git scripts that just notifies them that they should poll. There is no 
polling at fixed intervals then (e.g. daily, where a lot of commits need to be 
picked up at once, or every few minutes which might often find no commits and be a 
waste of resources), but neither does it create a bottleneck (SVN commits don't 
have to wait for mirrors to be updated before succeeding). Mirroring could just 
kick in a few seconds after each commit and pick it up.


Another possibility, and actually I think this is a good one, is to mirror to just 
Hg or Git, and then use Hg-git (a Mercurial extension) to mirror one from the 
other. Then only one mirror needs to interact with SVN, so the load is less, but 
we support both major DVCSes. The particularly nice thing about Hg-git is that it 
does changeset conversion losslessly, so if this is used, people using Hg and Git 
can collaborate, too. Conversion to/from SVN isn't lossless unfortunately. :-)


(For now, I'm just using hgsubversion to get SVN into a local Hg repo, but will 
change to use an official mirror basically immediately if we can create one, in 
order to help reduce the load.)


Ben.



On 28/04/11 2:30 PM, dukeofgaming wrote:

Hi Ben, I'm sorry I did a wrong remark there, but I see you saw what I
meant.

The nice thing about open source projects is that communities develop
naturally around them, it becomes an ecosystem, everything tends to lean
towards balance, when a change is intended to be made it should be allowed
to develop organically. Point here is: lets not try to force DVCSs but
rather keep the door open so the community can pass through it whenever it
feels ready, so the dilema of current devs vs potential devs never happens.

My advice here is —if current devs are willing— to pilot test a DVCS on a
small part of the project where it can be used primarily (as in not with
subversion); this would be a very healthy exercise to understand the why of
this generalized DVCS-ish concern.  Another advice is to open the discussion
towards the choice of a DVCS in comparison to the project's interests and
demographics (e.g. if there are more windows users than mac/linux, mercurial
would be preferred, if its the other way around  there is an underlying
git community, git might be best).

To all who doubt DVCS, this is a good read for you:
http://hginit.com/00.html

In relation to Drak's remarks, yes, I think the maturity of the tools has
contributed to its increased usage, and also, the very cool services around
them, such as github.com and bitbucket.org.

Finally, I think from here on, the conversation should be focused on finding
a technical solution to the load problem (I'm not familiar with the setup,
but if I think of something I'll post it).

Regards,

David

On Wed, Apr 27, 2011 at 10:29 PM, Ben Schmidtmail_ben_schm...@yahoo.com.au

wrote:



Just for the recordI didn't say popularity was a reason to use a DVCS.
I said the popularity of DVCSes might cause server strain (if a lot of
people want to convert the public SVN repo to a distributed one, downloading
all the changes in the repo, which SVN really wasn't designed for, that
would be a heavy load--and positively correlated to popularity: more
popular, more conversions, more load).

I agree with your closing point, though: I'd love to see us look for a
low-load way of providing an Hg mirror and/or a Git mirror. I also think
that either a mirror or a change of VCS may attract developers in the
medium-term. However, I also think that current developers carry a lot more
weight than potential developers, and it's important for them to be able to
work in a way that is comfortable for them. So a mirror or two would be
nice, and I'd push for that, but a change of official repo I will merely
suggest be considered longer term.

Ben.




On 28/04/11 1:07 PM, dukeofgaming wrote:


Hi,

I'm not a frequent poster in the list but I thought I'd really should give
my 1 cent here when I saw popular being an argument for using DVCSs, its
not, and its neither fashion nor cargo cult, it is just a plain eye opener
experience of how neither SVN or CVS are the base of all versioning (two
of
its creators —Brian Fitzpatrick and Ben Collins-Sussman— have acknowledged
this by saying sorry about that with regards to Subversion) and that
better and more natural ways to collaborate and integrate code.

I could provide an epically long argument here, but instead I'll link to
the
one I've already made, diagrams and graphics included =):


http://programmers.stackexchange.com/questions/35074/im-a-subversion-geek-why-i-should-consider-or-not-consider-mercurial-or-git-or/35080#35080

So, I don't want to make debate here of wether centralized is better 

Re: [PHP-DEV] Making SimpleXML more useful

2011-04-26 Thread Ben Schmidt
A similar problem regarding attributes, that got classified as a doc bug, but I 
don't think is one: http://bugs.php.net/42083


If you're fishing around that area of the code, though, perhaps it is quite 
obvious to you where/how a patch should be made?


Ben.



On 27/04/11 9:23 AM, Tom Samplonius wrote:


   It is not possible to use SimpleXML to add a child element without a 
namespace prefix to a parent element that has a namespace element. Instead, the 
child element inherits the namespace prefix of the parent. So this XML fragment:

ns1:parent
childabc/child
/ns1:parent

is impossible to construct with SimpleXML. The SimpleXML extension would add 
thechild  element with the ns1 namespace prefix. This is a problem for me, as 
I have an XML schema that specifies that the child elements must not namespace 
qualified.

   I looked into the SimpleXML code, and I believe this is actually a bug, as 
the code goes through some effort to distinguish between a set but blank 
namespace, and a set but not blank namespace. I believe the design intent was 
that specifying a blank namespace, would mean that no namespace would be used, 
rather than inheriting the namespace of the parent.

?php
header('Content-Type: text/plain');

$r = new SimpleXMLElement('r /');
$c1 = $r-addChild('ns1:child1', NULL, 'urn:myspace1');
$c1-addChild('child2');
echo $r-asXML(), \n;

$r = new SimpleXMLElement('r /');
$r-addChild('Thing1', 100, '');
echo $r-asXML(), \n;


Expected result:

?xml version=1.0?
rns1:child1 xmlns:ns1=urn:myspace1ns1:child2//ns1:child1/r

?xml version=1.0?
rThing1100/Thing1/r

Actual result:
--
?xml version=1.0?
rns1:child1 xmlns:ns1=urn:myspace1ns1:child2//ns1:child1/r

?xml version=1.0?
rThing1 xmlns=100/Thing1/r


   The current behavior of specifying a blank namespace, is to add a literal blank namespace 
(xmlns=), which isn't a useful result. No one would be depending on using a blank 
namepspace to get xmlns=.

The patch is pretty simple:

--- simplexml.c.orig 2011-04-26 16:00:31.0 -0700
+++ simplexml.c 2011-04-26 16:00:41.0 -0700
@@ -1619,12 +1619,14 @@
localname = xmlStrdup((xmlChar *)qname);
}

+ /* Add new child with no namespace */
newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value);

if (nsuri != NULL) {
+ /* If namespace is not NULL but blank, use no namespace
+ Use this to prevent inheriting the name space of the parent */
if (nsuri_len == 0) {
newnode-ns = NULL;
- nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix);
} else {
nsptr = xmlSearchNsByHref(node-doc, node, (xmlChar *)nsuri);
if (nsptr == NULL) {


(see also http://bugs.php.net/bug.php?id=54354)


If this patch is accepted, I'll also submit patches to clarify the 
documentation and add some tests. SimpleXML with the above patch, passes the 
existing tests. It is hard to know for sure what the design intent was, as the 
code has few comments, few tests, and the documentation is pretty thin. But I 
believe the above is correct.


Tom



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Making SimpleXML more useful

2011-04-26 Thread Ben Schmidt

I would expect the children() method to return just the last two elements of 
your input XML:

root xmlns=http://localhost/a; xmlns:ns=http://localhost/a;
elem attr=abc/
elem ns:attr=abc/
ns:elem attr=abc/
ns:elem ns:attr=abc/
/root

as the last two elements are the only ones in the 'http://localhost/a' 
namespace.


No, every element in the document is in the same namespace. The first
two children and the root element are in the namespace by virtue of the
default namespace of the root element; the last two are in the namespace
by virtue of an explicit prefix.

To have those children have no default namespace, it would be necessary
to write something like this:

root xmlns=http://localhost/a; xmlns:ns=http://localhost/a;
elem xmlns= attr=abc/
elem xmlns= ns:attr=abc/
ns:elem attr=abc/
ns:elem ns:attr=abc/
/root

See:

http://www.w3.org/TR/xml-names/#scoping-defaulting

The indentation of the examples is a bit messed up, but you'll see the
same thing done there.

Attributes, however, are a different story. Attributes always need an
explicit prefix to be in a namespace.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Making SimpleXML more useful

2011-04-26 Thread Ben Schmidt

Looking at this in more detail...I don't think there's a bug here, or a
patch required.


It is not possible to use SimpleXML to add a child element without a
namespace prefix to a parent element that has a namespace element.
Instead, the child element inherits the namespace prefix of the
parent. So this XML fragment:

ns1:parent
childabc/child
/ns1:parent

is impossible to construct with SimpleXML. The SimpleXML extension
would add the child element with the ns1 namespace prefix. This is a
problem for me, as I have an XML schema that specifies that the child
elements must not namespace qualified.


Is this possible in an XML schema? I don't know much about schemas, but
just about the XML language itself, but I would have expected a schema
only cared about what namespaces elements were in, not whether they were
prefixed or not. E.g. I would have expected these to be equivalent:

ns1:parent xmlns:ns1=whatever
child xmlns=abc/child
/ns1:parent

ns1:parent xmlns:ns1=whatever
childabc/child
/ns1:parent

parent xmlns=whatever
child xmlns=abc/child
/parent

ns1:parent xmlns=whatever xmlns:ns1=whatever
child xmlns=abc/child
/ns1:parent

I would also expect, if the child were to be namespaced, that these are
equivalent:

ns1:parent xmlns=whatever xmlns:ns1=whatever
childabc/child
/ns1:parent

ns1:parent xmlns:ns1=whatever
ns1:childabc/ns1:child
/ns1:parent

parent xmlns=whatever
childabc/child
/parent


$r = new SimpleXMLElement('r /');
$c1 = $r-addChild('ns1:child1', NULL, 'urn:myspace1');
$c1-addChild('child2');
echo $r-asXML(), \n;


This should add child2 in the same namespace as child1, as no namespace
is given explicitly for child2. So I would expect

rns1:child1 xmlns:ns1=urn:myspace1ns1:child2 //ns1:child1/r

or

rchild1 xmlns=urn:myspace1child2 //child1/r


$r = new SimpleXMLElement('r /');
$r-addChild('Thing1', 100, '');
echo $r-asXML(), \n;


I would expect

rThing1100/Thing1/r


Expected result:

?xml version=1.0?
rns1:child1 xmlns:ns1=urn:myspace1ns1:child2//ns1:child1/r


This matches my expectation, too.


?xml version=1.0?
rThing1100/Thing1/r


And this.


Actual result:
--
?xml version=1.0?
rns1:child1 xmlns:ns1=urn:myspace1ns1:child2//ns1:child1/r


This matches our expectations.


?xml version=1.0?
rThing1 xmlns=100/Thing1/r


This doesn't match, but is equivalent, so acceptable.


The current behavior of specifying a blank namespace, is to add a
literal blank namespace (xmlns=), which isn't a useful result. No
one would be depending on using a blank namepspace to get xmlns=.


No, consider this code.

$r = new SimpleXMLElement('r xmlns=urn:myspace1 /');
$r-addChild('Thing1',100,'');
echo $r-asXML(), \n;

I expect

r xmlns=urn:myspace1Thing1 xmlns= //r

and the xmlns= is necessary. If this functionality were removed, how
could this be done?

Sure, SimpleXML could perhaps output XML that is slightly more
efficient/less verbose than it currently does, but its output is not
incorrect, and the functionality you want to remove is necessary in
other circumstances.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Call non-static method staticly raise E_STRICT, but why call a static method instancely won't

2011-04-25 Thread Ben Schmidt

Back in PHP4 it was the only way to simulate an static call, but
nowadays it really don't make sense at all.

class Foo {
  static function toString(Bar $bar) {
   return 'Foo::toString($bar)';
  }
  function toString() {
   return '$this-toString()';
  }
}

$foo = new Foo();
echo $foo-toString(); // instance
echo Foo::toString(); // class

PHP will complain about the 2nd method (can't redefine function) but for me
are 2 completely different methods.
I belive the current Object Model could be improved. isn't?


I agree. Backward compatibility is the only reason to keep this. It's a
pretty compelling reason, though. It's hard to know how to phase it out
non-invasively, too.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Function proposal: varset

2011-04-22 Thread Ben Schmidt

yeah you are right, passing arguments by reference doesn't trigger the
notice, but I'm not sure that it is applicable in our case.


Yeah, it wouldn't help. For instance, 42 or default can't be passed by
reference, so you couldn't actually provide a default value to
coalesce() if you implemented it like that, which would make it pretty
useless. :-)

Ben.





--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-22 Thread Ben Schmidt

On 21/04/11 9:56 AM, Arpad Ray wrote:

I must say that the prospect of yet more new syntax is scary. It
really looks like Perl, and I wouldn't have the slightest clue what it
meant if I'd missed the release notes.


I agree it looks a little bit strange. I think that's partly a benefit:
it doesn't look like something so that you assume you know what it means
but get it wrong; it drives you to the manual to find out what it means.


I've pined for something like coalesce($_GET['foo'], $defaults['foo'],
42) for years, and I think that style is far more in keeping with the
PHP ethos, and far more readily understandable than this suggested new
syntax.


As I see it, there a are a number of drawbacks to this approach.

1. It doesn't help with a bunch of common paradigms. For instance,
$a['k'] = isset($a['k']) ? $a['k'] : default

2. I think it's too 'blunt'. For instance, if you write
coalesce($_GET['foo'], $defaults['foo']) you probably actually do want
to see a notice if $defaults['foo'] is not defined. But if you include
42 as a last resort default, you of course do not. Treating the last
argument of a variable number of arguments differently is difficult and
unintuitive, and even that would not always be desired anyway.
Furthermore with something like $o-foo are you interested in whether $o
is defined or not, or only in whether $o-foo is null? Particularly if
you have many arguments, if you don't have tests that give full coverage
of all the possibilities for each argument, notices very helpful for
debugging could be easily undesirably silenced.

3. It can't be equivalent to isset() on every argument. isset() is very
restricted in what it can operate on. For instance, isset(42) is not
legal; nor is isset(some_function()); and so on. This kind of thing
would be important to allow in coalescse(), but it would make things
difficult to parse: to have any chance of making it work, you'd need to
parse each item as if in isset(), and if it fails, backtrack and parse
it as an expression, and then the coalesce() operation(s) (it could not
be a function) would have to be able to deal with both scenarios for
every argument. Nasty.

4. It's misleading regarding side effects because it looks like a
function. If coalesce() were a function and you wrote
coalesce($_GET['foo'],get_default('foo')), you would expect
get_default() to be called before coalesce() and regardless of the state
of $_GET['foo']. If it actually behaved like that, it would render
coalesce() somewhat less useful, but it would be misleading if it didn't
work like that. isset() gets away with this because it is restricted and
only has one argument, but coalesce() wouldn't.

To avoid/solve these problems:

1. Support missing paradigms: I suppose adding coalesce_set() and other
constructs could conceptually provide for that.

2. Less blunt: You really need some kind of notice-free array index
and/or variable lookup that can pinpoint the notice to be omitted. A
function-like syntax doesn't really work: isset(), though better than
coalesce(), is still too blunt for many use cases. It's also very
verbose. Nobody wants to write
coalesce(ifset($_GET['foo']),ifset($defaults['foo']),42)
IMHO, it is better to have
coalesce($_GET[?'foo'],$defaults[?'foo'],42)
even though it's not 'familiar'.

3. Avoid isset()-like restrictions: You can use a !==null test that can
be applied to any expression; if problem 1 is solved satisfactorily, an
expression will simply be evaluated without generating a notice, and
then compared to null.

4. Sensible side-effect behaviour: To get that, you really need an
operator (or other language construct), and a function-like syntax is
misleading. Although unfamiliar,
$_GET[?'foo'] $: $defaults[?'foo'] $: 42
is less misleading. It also extends nicely to the assignment paradigm as
$_GET[?'foo'] $:= $defaults[?'foo'] $: 42;

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-22 Thread Ben Schmidt

What does coalesce() do?
If I'm guessing correctly, would  proposal #2 that Rune Kaagaard put up
solve that for you?
https://gist.github.com/909711


Rune's proposal #2, extending func_get_arg(), is impossible to
implement/would not work.

His proposal #3, which is more like coalesce(), suffers from the
drawbacks/problems of coalesce() which I discussed in a recent post
(though you can see Rune has some workarounds/hacks to deal with some of
the problems).

IMHO, his proposal #1 is the only real contender. However, I believe it
conflates two problems which others do not want conflated. He briefly
dismisses the [?] syntax, because it addresses what he sees as a
different problem. However, that different problem is really part of his
problem. My contention is that the two parts of his problem are better
solved independently (notice-suppression separately to finding an
isset/!empty value), and furthermore that one of the two versions of his
problem is already partially solved and should be reused, not reinvented
(existing ternary operator for a !empty check).

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-22 Thread Ben Schmidt
It's good for some situations, but there are plenty more where it doesn't cut it, 
e.g. $_GET[?'foo'] $:= get_default_from_db('foo') $: hard-coded.


Ben.



On 23/04/11 12:54 PM, Martin Scotta wrote:

what about something like this?

  $_GET += array( 'key' =  42, 'other' =  'blablah' );

echo $_GET [ 'key' ];

and it's already available on you current instalation :)

  Martin Scotta


On Fri, Apr 22, 2011 at 11:27 PM, Ben Schmidtmail_ben_schm...@yahoo.com.au

wrote:



On 21/04/11 9:56 AM, Arpad Ray wrote:


I must say that the prospect of yet more new syntax is scary. It
really looks like Perl, and I wouldn't have the slightest clue what it
meant if I'd missed the release notes.



I agree it looks a little bit strange. I think that's partly a benefit:
it doesn't look like something so that you assume you know what it means
but get it wrong; it drives you to the manual to find out what it means.


  I've pined for something like coalesce($_GET['foo'], $defaults['foo'],

42) for years, and I think that style is far more in keeping with the
PHP ethos, and far more readily understandable than this suggested new
syntax.



As I see it, there a are a number of drawbacks to this approach.

1. It doesn't help with a bunch of common paradigms. For instance,
$a['k'] = isset($a['k']) ? $a['k'] : default

2. I think it's too 'blunt'. For instance, if you write
coalesce($_GET['foo'], $defaults['foo']) you probably actually do want
to see a notice if $defaults['foo'] is not defined. But if you include
42 as a last resort default, you of course do not. Treating the last
argument of a variable number of arguments differently is difficult and
unintuitive, and even that would not always be desired anyway.
Furthermore with something like $o-foo are you interested in whether $o
is defined or not, or only in whether $o-foo is null? Particularly if
you have many arguments, if you don't have tests that give full coverage
of all the possibilities for each argument, notices very helpful for
debugging could be easily undesirably silenced.

3. It can't be equivalent to isset() on every argument. isset() is very
restricted in what it can operate on. For instance, isset(42) is not
legal; nor is isset(some_function()); and so on. This kind of thing
would be important to allow in coalescse(), but it would make things
difficult to parse: to have any chance of making it work, you'd need to
parse each item as if in isset(), and if it fails, backtrack and parse
it as an expression, and then the coalesce() operation(s) (it could not
be a function) would have to be able to deal with both scenarios for
every argument. Nasty.

4. It's misleading regarding side effects because it looks like a
function. If coalesce() were a function and you wrote
coalesce($_GET['foo'],get_default('foo')), you would expect
get_default() to be called before coalesce() and regardless of the state
of $_GET['foo']. If it actually behaved like that, it would render
coalesce() somewhat less useful, but it would be misleading if it didn't
work like that. isset() gets away with this because it is restricted and
only has one argument, but coalesce() wouldn't.

To avoid/solve these problems:

1. Support missing paradigms: I suppose adding coalesce_set() and other
constructs could conceptually provide for that.

2. Less blunt: You really need some kind of notice-free array index
and/or variable lookup that can pinpoint the notice to be omitted. A
function-like syntax doesn't really work: isset(), though better than
coalesce(), is still too blunt for many use cases. It's also very
verbose. Nobody wants to write
coalesce(ifset($_GET['foo']),ifset($defaults['foo']),42)
IMHO, it is better to have

coalesce($_GET[?'foo'],$defaults[?'foo'],42)
even though it's not 'familiar'.

3. Avoid isset()-like restrictions: You can use a !==null test that can
be applied to any expression; if problem 1 is solved satisfactorily, an
expression will simply be evaluated without generating a notice, and
then compared to null.

4. Sensible side-effect behaviour: To get that, you really need an
operator (or other language construct), and a function-like syntax is
misleading. Although unfamiliar,

$_GET[?'foo'] $: $defaults[?'foo'] $: 42
is less misleading. It also extends nicely to the assignment paradigm as
$_GET[?'foo'] $:= $defaults[?'foo'] $: 42;

Ben.





--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php






--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-20 Thread Ben Schmidt

On 17/04/11 9:14 AM, Ángel González wrote:

Ben Schmidt wrote:

$var = $arr['key'] ?? : 'empty';


Also note this is possible with the recent proposal Hannes and I were
discussing. It simply looks like

$var = $arr?['key'] ?: 'empty';

The ?[ avoids notices and the ?: works as it always has.

Ben.


If it was going to be ?[, I'd much prefer $arr['key'?]. It was proposed as
$arr[?'key'] instead to avoid a backtracking (would that really be
noticeable?
I'd prefer readibility), but ?[ would have the same problem.


The backtracking issue was part of a different proposal where a ternary
operator had an optional 'else' part. It is not an issue with
notice-free array lookups as more recently proposed, and I see no reason
we couldn't use ?[ or [? or ?] as the syntax. In all cases, either that
combination of characters can be scanned as a single token, or the
parsing can be done with just one token of lookahead and no
backtracking. I don't know what kind of parser PHP uses, though, so I'm
just guessing; but AFAICT any standard kind of parser shouldn't have
much trouble here.

The one argument I can find for favouring ?[ or [? is that this
generalises more naturally. Perhaps [? is the best. It generalises
nicely if required:

$array[?'key']
$?variable
$object-?property

I personally only think we need the first one, but there are a few votes
for the second, too. I personally also don't care very much about the
syntax; I'd be equally happy with $array['key'?] or $array?['key']. I'm
just keen to have the functionality (and separately, the !==null
operator(s)).

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-16 Thread Ben Schmidt

I believe describing nullness checking as a main issue is a rather
strong assessment.


I don't think so, obviously. :-)


$var = (isset($arr['key'])) ? $arr['key'] : 'empty';


Nullness checking is half of what that code does, isn't it? Otherwise it
would be (isset($arr['key'])  $arr['key']), right?


Additionally, it might not be as succinct as you prefer, but surely

$var = $arr['key'] ?? : 'empty';

is a significant improvement over the current means and does in fact remove
redundant code.


But it's not equivalent to your code snippet above, is it?

My vote's still with the line of discussion Hannes and I were on, of
separate 'careful array index lookup' and 'default-when-null'
operator(s). Partly because I think that approach can help everyone,
whereas the checked ternary operator really doesn't help me much at all.
Not sure if that's selfish or not. :-)

I'll try to stay a bit quieter for a bit, if I can manage it I've
said a lot today.

Returning due respect,

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-16 Thread Ben Schmidt

$var = $arr['key'] ?? : 'empty';


Also note this is possible with the recent proposal Hannes and I were
discussing. It simply looks like

$var = $arr?['key'] ?: 'empty';

The ?[ avoids notices and the ?: works as it always has.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-15 Thread Ben Schmidt

That sounds fine to me, and the extension to ArrayAccess is really
clever. I agree that 'take more care' is a better way to view the array
access. It means both the array access should be more careful (to check
and avoid errors, rather than just proceed), and also the 'caller'
should be more careful by being more prepared to accept null values. I
don't know if ? is the best character to represent this, but I don't
really care--I'd just be glad of the functionality. Perhaps ! is another
possibility worth considering, though.

If 7 and 8 are included, there are actually then four new constructs:

- $: operator that evaluates to LHS if !==null, RHS otherwise
- $:= assignment only if the LHS is null or undefined (return final LHS)
- ?[...] array index lookup without notice (and ArrayAccess extension)
- $?name variable lookup without notice

I'd be happy with that. The only one I'm not so sure about is the last
one.

Ben.

(P.S. My earlier example for 7 was slightly wrong; it should require
what is now the ?[...] construct to avoid the notice; other compound
assignment operators like += produce notices. I've modified it below.)



On 15/04/11 8:12 PM, Hannes Landeholm wrote:

I like this - especially .7 and .8.

The $: is intuitive because it looks like a variable that doesn't contain
anything and the : specifies what comes then.

However I'd rather use the ? character than @ for the simple reason that
I see this as a more careful way to access an array and not as an error
silencing operation. E.g. it's not implemented by setting error reporting
to 0 but rather... to illustrate it, let's pretend that the PHP array where
implemented by the ArrayAccess class. The offsetGet signature would be
changed too take an extra argument:

offsetGet( mixed $offset, boolean $unset_defined )

Normal array access would have $unset_defined set to false, but an access
like $a?[$k] would set it to true (the ?[ modifier) would make
$unset_defined become true so:

if (!$unset_defined) {
\trigger_error(Undefined index: $offset, \E_NOTICE);
}
return null;

Of course, in userland, one could implement ArrayAccess and exploit the
$unset_defined parameter in any other way. Let's for example say that you
implement it to make an ArrayAccess class that maps data to the file system,
using the file name as a $offset. If $unset_defined is set to false you
would just go ahead and try to open the file in question, possibly raising a
file operation error - however if $unset_defined is true you might make a
careful check before opening the file to see if it really exist. If error
silencing would be used instead - other errors like file permission errors
could incorrectly be silenced - but $unset_defined specifically checks if
the file exist or not before access. So it could affect the read operation
itself - and I hope that explains why It's more than just error silencing.

~Hannes

On 15 April 2011 03:01, Ben Schmidtmail_ben_schm...@yahoo.com.au  wrote:


I agree empty() is basically useless. We already have the existing
ternary operator (and its shortcut) to do a boolean test, which is
basically the same as empty().

The way I see it, if rather than making an isset() operator that
suppresses errors and offers a default, we added both a !==null operator
for the default, and a separate error-suppression mechanism, people
could use the suppression mechanism with the existing boolean ternary
operator if they want to (I would find that useful, as I often write
things such as isset($a[$k])$a[$k]?yes:no for that kind of thing),
and use the !==null operator without error suppression (I would find
that useful, too, to avoid typos).

In summary, with two separate, simpler mechanisms, we could tackle these
paradigms (I have used @[...] for undefined index error-suppression and
$: for !==null default):

1. $v!==null ? $v : default
   $v $: default
   with notice

2. $a[$k]!==null ? $a[$k] : default
   $a[$k] $: default
   with notice

3. isset($a[$k]) ? $a[$k] : default
   $a@[$k] $: default
   without notice

4. isset($a[$k]) ? $a[$k] : null
   $a@[$k]
   without notice

5. isset($a[$k])!!$a[$k]
   !!$a@[$k]
   without notice

6. isset($a[$k])$a[$k] ? yes : no
   $a@[$k] ? yes : no
   without notice

With !==null assignment (I've used $:=) we could also have:

7. if (!isset($a[$k])) $a[$k] = default;
   $a@[$k] $:= default;
   without notice

To avoid encouraging poor coding, we would deliberately not have:

8. isset($v) ? $v : default
   $@v $: default
   without notice

But it is a cinch to add it if enough people want it, and doing so
wouldn't affect anyone who didn't want to use it--no backward
compatibility problems on the horizon. I think that's the clincher. If
we just add an isset() operator (that suppresses errors, and gives a
default), we only get paradigms 3, 4, 5 and maybe 7, but worse, if we
want to add any of the others later, we need to design more complicated
new operators, or break backward compatibility, not just extend what we
have.

I 

Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-15 Thread Ben Schmidt

There was also my suggestion of a checked ternary operator [see my
previous email in this thread.] Backwards compatible, practical, and simple.


It doesn't address the main issues of code duplication and nullness
checking, IMHO, so isn't a contender. Even though it's simple and
compatible, it is only practical in a handful of cases.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-14 Thread Ben Schmidt

1. Suppression of notice. I agree, it is best done only for array
keys. It's not hard to initialise a variable with $var=null at the
beginning of a code block to avoid such a notice, and that is the
appropriate way to do it for variables.

2. Offering a shortcut for the common idiom isset($x) ? $x : $y in
line with the DRY design principle. A notice would never be emitted
here in any case. The problem is that this idiom is still in wide use
despite the shortcut ternary operator already provided, because an
isset() check is different to a boolean cast.

Some thoughts:

- The actual intent of 2. is probably $x!==null ? $x : $y i.e. it's
not about suppressing notices at all, but about offering a default
value, and the idiom quite probably only uses isset() because it
predated null in the language.


I have never felt the need for a shortcut in these cases. It would be
interesting to see some code where this would be practical.


I have many, many uses for this. E.g. patterns like this:

class Foo {
   private $defaultBar;
   public function foobar(Bar $bar=null) {
  $bar = isset($bar) ? $bar : $this-defaultBar;
  $bar-doSomething();
   }
}

The default value of null indicates that the argument is able to be
omitted, and the type hinting mechanism understands that. Yet it's
awkward to actually test whether it's been omitted or not without
writing the argument multiple times. It'd be great to be able to write
the first line succinctly, e.g.

$bar $:= $this-defaultBar;

That's just one case. There are many more.

As I said above, though, I probably should have written $bar!==null
rather than isset($bar), because I actually would want the warning if
$bar was not defined (i.e. I had mistyped it).


- If we view 2. in this way, the two problems are independent, and it
seems to me it would be best to solve them independently, rather
than with a single operator.

So, I suggest:

1. An array lookup mechanism that suppresses the notice for undefined
keys. It would work the same as regular array index lookups except
that the notice for undefined keys (and only for undefined keys)
would not be generated (it would not just be hidden, but would never
be even generated).


This is what I feel PHP is missing. Particularly when it comes to
multi-dimensional arrays. Because this feature is missing I tend to do
something like

function generateHash($x, $y, $z)
{
return $x::$y::$z;
}

if (isset($a[generateHash($x, $y, $z)]) {
...
}

instead of

if (isset($a[$x])  isset($a[$x][$y])  isset($a[$x][$y][$z])) {
...
}


I don't really understand your example, or how an error-suppressing
array index lookup helps it, but I do think the feature is useful.

I actually think there is enough support for both these things, and
implementing them independently allows those who want to use one but not
the other to do so.


Arguing about syntax is then a second step. However, my views on this
are:


I think it best to avoid discussing the actual syntax before agreeing on what we
really need.


I agree. In fact I sent the previous mail by mistake; I had intended to
archive my thoughts on syntax and send the mail without them, but I
bumped send.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-14 Thread Ben Schmidt

On 14/04/11 10:08 PM, Jordi Boggiano wrote:

On 14.04.2011 13:58, Ben Schmidt wrote:

I have many, many uses for this. E.g. patterns like this:

class Foo {
private $defaultBar;
public function foobar(Bar $bar=null) {
   $bar = isset($bar) ? $bar : $this-defaultBar;
   $bar-doSomething();
}
}


I'm sorry but this is not a valid use case, isset() is totally
unnecessary here. You can use

   $bar = $bar ?: $this-defaultBar;

Of course it still repeats $bar, but it's not that verbose, and will
work exactly the same as what you do. I'd argue it's even better than
what you do because, if it weren't for that Bar type hint, if someone
passes false or blah to your function, isset() will return true, and
you'll try to call doSomething on false/blah, which is a cute fatal error.


Actually, you'll get a cute fatal error when the function is called
because of the type hint in that case.

Anyway, yeah, sure, perhaps a bad example in its detail. I didn't spend
hours composing it. Just use a little imagination, though, and imagine
that it wasn't a type hinted object coming in, but some other value like
an integer. Then a boolean test would not work (would be false for zero
and erroneously use the default value). You then need the isset test. I
personally prefer to always use an isset/key_exists/is_null test when
I'm testing for something's 'existence' and not its 'truth'. I think
that makes the code more readable.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-14 Thread Ben Schmidt

There are two issues here.

1. Suppression of notice. I agree, it is best done only for array
keys. It's not hard to initialise a variable with $var=null at the
beginning of a code block to avoid such a notice, and that is the
appropriate way to do it for variables.

2. Offering a shortcut for the common idiom isset($x) ? $x : $y in
line with the DRY design principle. A notice would never be emitted
here in any case. The problem is that this idiom is still in wide use
despite the shortcut ternary operator already provided, because an
isset() check is different to a boolean cast.

Some thoughts:

- The actual intent of 2. is probably $x!==null ? $x : $y i.e. it's
  not about suppressing notices at all, but about offering a default
  value, and the idiom quite probably only uses isset() because it
  predated null in the language.

- If we view 2. in this way, the two problems are independent, and it
  seems to me it would be best to solve them independently, rather
  than with a single operator.

So, I suggest:

1. An array lookup mechanism that suppresses the notice for undefined
keys. It would work the same as regular array index lookups except
that the notice for undefined keys (and only for undefined keys)
would not be generated (it would not just be hidden, but would never
be even generated).


http://news.php.net/php.internals/51877

array_key_exists($key, $array) for arrays
array_key_exists($varname, get_defined_vars()) for locally scoped variables.


Apart from being long and ugly, surely that is horribly inefficient.


No need to use @.


True. And I don't think anybody is. We all know @ is dangerous and nasty
and don't use it. We're not seeking an alternative to @, we're seeking
an alternative to repeating ourselves by using
isset()/array_key_exists()/is_null() as well as the value being tested.

But we don't want to do this in a blanket way similar to @ where a whole
bunch of notices are suppressed. We want to specify precisely where
missing values are allowable by indicating exactly which array index
lookups may silently fail (and evaluate to null).

Basically we don't want to make again the mistake that @ was.


Are they attempting to determine the existence of a variable/index
entry or are they attempting to determine if the variable/element is
null.


For me, existence and nullness are basically the same, and I think this
is the common case. The whole point of being able to set something to
null is to have a 'value' to represent 'unsetness'. This is why I think
solving the conditional problem should use a !==null test. That gives
the flexibility to use/pass null to represent 'unsetness' but doesn't
pick up zero, false, etc. like a boolean cast does. Using
array_key_exists() would remove that flexibility and be less useful.

As far as silencing notices goes, the rationale is that basically we
want to flag that 'null is OK, even if it's a fallback'. I.e. we don't
care whether a value is null because it was set to null, or because null
is a fallback because the variable was never defined. Either way, null
is OK, so don't tell me about it.

The conditional side lets us handle nulls nicely by providing our own
defaults/fallbacks if it appears. The notice-suppression side lets us
say that null is OK, even if that null itself is a fallback for
'undefined'. Quite often they will be used in combination, but they are
independent.


I always declare my variables. So, I don't want to use isset() as they
will be an incorrect test. I use is_null(). Specifically testing the
value. If I've made a mistake and NOT declared the variable (or made a
typo), I want to know. I don't want to hide it with isset()/empty().


That's exactly why I think the conditional should use a !==null test,
not an isset() test.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-14 Thread Ben Schmidt

I cry whenever I see code with @ in it...


I don't like @ either. The whole point of this proposal though is to
offer a safe alternative, a way to suppress only those notices which are
being accounted for by the programmer and no more, without messing
around making a custom error handler that ignores one type of error,
which is the current way to do it 'safely'.


What we're wanting are existential assignment and ternary operators.
Simply put, a painless way to set or use a default value based on the
existence of a variable without needing a bunch of extra code to avoid
notices/errors. Sorry Ben, but I think extending the @ operator to
prevent errors from being generated in the first place is a terrible
idea. I would prefer to see @ removed from PHP if possible.


I never meant to extend @, I meant simply to reuse that symbol--i.e. the
@ character--as part of the syntax of a new safer feature, since it
performed a similar function. The actual @ operator is not changed in
any way. Rather, a new @[...] array indexing mechanism is added which
suppresses the Undefined Index notice, and only that notice, by not
generating it.


I would also want this to work with objects and scalars. It would be
particularly useful within view scripts where the values are passed in
via extract, or as object properties, and you can't instantiate them
first because that would clear them.


I guess that's a vaguely valid use case, though I still somewhat think
it is the responsibility of the caller of the view script to ensure all
variables are instantiated (to null if appropriate). I guess an
unambiguous syntax for this could be $@variable.

I guess object properties are another case. I wonder how common. I guess
$object@-property would be the way to deal with that.

I still lean towards just offering it for arrays, though. That seems to be
the area of greatest need by a significant margin.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-14 Thread Ben Schmidt
Sometimes this is true, but sometimes not. For example, HTTP GET/POST interfaces 
often have optional parameters. These need to be tested for, and often defaults 
provided, to write solid code.


Saying you can always wrap it is like saying you can write your programs for a 
Turing machine.


Also, not everyone is writing highly abstracted object-oriented code in PHP.

Ben.



On 14/04/11 11:25 PM, Martin Scotta wrote:

arrays are intent for holding values, not for represent things so use objects 
for
that.
the need for array_key_exists/isset to check for the presence of an index is a
smell that you need to refactor your code for a different datatype.

If you cannot change the array, you always can wrap it.

With good data abstractions the usage of array_key_exists/isset/empty is barely
reduced to the minimum.

  Martin Scotta


On Thu, Apr 14, 2011 at 10:12 AM, Ben Schmidt mail_ben_schm...@yahoo.com.au
mailto:mail_ben_schm...@yahoo.com.au wrote:

There are two issues here.

1. Suppression of notice. I agree, it is best done only
for array
keys. It's not hard to initialise a variable with
$var=null at the
beginning of a code block to avoid such a notice, and 
that
is the
appropriate way to do it for variables.

2. Offering a shortcut for the common idiom isset($x) ? 
$x
: $y in
line with the DRY design principle. A notice would never
be emitted
here in any case. The problem is that this idiom is 
still
in wide use
despite the shortcut ternary operator already provided,
because an
isset() check is different to a boolean cast.

Some thoughts:

- The actual intent of 2. is probably $x!==null ? $x : 
$y
i.e. it's
  not about suppressing notices at all, but about 
offering
a default
  value, and the idiom quite probably only uses isset()
because it
  predated null in the language.

- If we view 2. in this way, the two problems are
independent, and it
  seems to me it would be best to solve them
independently, rather
  than with a single operator.

So, I suggest:

1. An array lookup mechanism that suppresses the notice
for undefined
keys. It would work the same as regular array index
lookups except
that the notice for undefined keys (and only for 
undefined
keys)
would not be generated (it would not just be hidden, but
would never
be even generated).

http://news.php.net/php.internals/51877

array_key_exists($key, $array) for arrays
array_key_exists($varname, get_defined_vars()) for locally scoped 
variables.


Apart from being long and ugly, surely that is horribly inefficient.

No need to use @.


True. And I don't think anybody is. We all know @ is dangerous and nasty
and don't use it. We're not seeking an alternative to @, we're seeking
an alternative to repeating ourselves by using
isset()/array_key_exists()/is_null() as well as the value being tested.

But we don't want to do this in a blanket way similar to @ where a whole
bunch of notices are suppressed. We want to specify precisely where
missing values are allowable by indicating exactly which array index
lookups may silently fail (and evaluate to null).

Basically we don't want to make again the mistake that @ was.


Are they attempting to determine the existence of a variable/index
entry or are they attempting to determine if the variable/element is
null.


For me, existence and nullness are basically the same, and I think this
is the common case. The whole point of being able to set something to
null is to have a 'value' to represent 'unsetness'. This is why I think
solving the conditional problem should use a !==null test. That gives
the flexibility to use/pass null to represent 'unsetness' but doesn't
pick up zero, false, etc. like a boolean cast does. Using
array_key_exists() would remove that flexibility and be less useful.

As far as silencing notices goes, the rationale is that basically we
want to flag that 'null is OK, even if it's a fallback'. I.e. we don't
care whether a value is null because it was set to null, or because null

Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-14 Thread Ben Schmidt

On 15/04/11 12:05 AM, Hannes Landeholm wrote:

Trying to summarize this discussion... I think we can all agree that the
main problem is code duplication for array access when parameters are
possibly not existing.


For me the problem is 'code duplication when a value might be null'
(whether an array, variable or something else, and regardless of whether
it was set to null, or not defined at all).


I think we all can also agree that @ can be both used properly and
misused - and it is a blunt tool and not a nice solution to the
previously stated problem.


Yes.


Some suggested that the ternary if comparison should suppress the notice
automatically. This would break existing code and also be confusing since
people expect a ternary if and normal if to work the same way.


Yes.


Some suggested ?? as an array access operator that suppresses the notice and
has 3 variants: A: nothing specified - uses null as default, B: has default
specified, C: returns X if index exists or Y if index doesn't exist. This
effectively solves the code duplication problem and is a shortcut for saying
the array index may or may not exist.


This only works if the test is made an isset() kind of test. If it
remains a boolean cast, it doesn't help much. (Or at least it doesn't
help me much.)

I also think it's a bit too blunt. In all but the simplest expressions
in the condition, desired notices could be silenced. I like the idea of
being able to specify exactly which array lookups should be silenced.

It also doesn't help the people who want an isset() style test, but
without the notice suppression, and I think there are a few people in
that category.


One person said that the relation between ? and ?? and == and === would make
the operator non-intuitive. Other people disagreed and claimed the opposite.

So basically the discussion now is what exact characters that should be used
to represent this operator? I really hope we can get this implemented
quickly... I worked with $_POST yesterday and I could really use that ??
operator.


I still don't think we've reached agreement on exactly what we need.
Your summary seems to me to be of some of the earliest and least
developed ideas. I think the discussion has moved in a number of
interesting directions since then and we should draw on that later work.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-14 Thread Ben Schmidt

I agree empty() is basically useless. We already have the existing
ternary operator (and its shortcut) to do a boolean test, which is
basically the same as empty().

The way I see it, if rather than making an isset() operator that
suppresses errors and offers a default, we added both a !==null operator
for the default, and a separate error-suppression mechanism, people
could use the suppression mechanism with the existing boolean ternary
operator if they want to (I would find that useful, as I often write
things such as isset($a[$k])$a[$k]?yes:no for that kind of thing),
and use the !==null operator without error suppression (I would find
that useful, too, to avoid typos).

In summary, with two separate, simpler mechanisms, we could tackle these
paradigms (I have used @[...] for undefined index error-suppression and
$: for !==null default):

1. $v!==null ? $v : default
   $v $: default
   with notice

2. $a[$k]!==null ? $a[$k] : default
   $a[$k] $: default
   with notice

3. isset($a[$k]) ? $a[$k] : default
   $a@[$k] $: default
   without notice

4. isset($a[$k]) ? $a[$k] : null
   $a@[$k]
   without notice

5. isset($a[$k])!!$a[$k]
   !!$a@[$k]
   without notice

6. isset($a[$k])$a[$k] ? yes : no
   $a@[$k] ? yes : no
   without notice

With !==null assignment (I've used $:=) we could also have:

7. if (!isset($a[$k])) $a[$k] = default;
   $a[$k] $:= default;
   without notice (the LHS of an assignment never generates one)

To avoid encouraging poor coding, we would deliberately not have:

8. isset($v) ? $v : default
   $@v $: default
   without notice

But it is a cinch to add it if enough people want it, and doing so
wouldn't affect anyone who didn't want to use it--no backward
compatibility problems on the horizon. I think that's the clincher. If
we just add an isset() operator (that suppresses errors, and gives a
default), we only get paradigms 3, 4, 5 and maybe 7, but worse, if we
want to add any of the others later, we need to design more complicated
new operators, or break backward compatibility, not just extend what we
have.

I personally use 1, 3, 5 and 6 quite often, and 2 and 7 occasionally, so
I see great value in being able to do them all, not just the restricted
set.

What numbers are others interested in being able to solve?

What do others think about the future-proofing issue?

Ben.



On 15/04/11 1:01 AM, Hannes Landeholm wrote:

I can agree that implementing ?? with isset() and not array_key_exists() would 
be
acceptable... but empty() is a blunt compromise and much less used... The 
general
problem is the notice being thrown when array indexes doesn't exist - which
results in code duplication when you deal with it nicely. empty() tries to be a
generic solution but there will always be people that has some other special
definition of emptiness like array that contains a single null value and 
they
need to write the code that defines that particular comparison anyway.

You can't have a solution that makes everything easier for everyone so let's 
solve
one thing at a time and start with the most generic problem specifically and not
all minor problems that happens to partially intersect that one.

~Hannes


On 14 April 2011 16:26, Ben Schmidt mail_ben_schm...@yahoo.com.au
mailto:mail_ben_schm...@yahoo.com.au wrote:

On 15/04/11 12:05 AM, Hannes Landeholm wrote:

Trying to summarize this discussion... I think we can all agree that the
main problem is code duplication for array access when parameters are
possibly not existing.


For me the problem is 'code duplication when a value might be null'
(whether an array, variable or something else, and regardless of whether
it was set to null, or not defined at all).


I think we all can also agree that @ can be both used properly and
misused - and it is a blunt tool and not a nice solution to the
previously stated problem.


Yes.


Some suggested that the ternary if comparison should suppress the notice
automatically. This would break existing code and also be confusing 
since
people expect a ternary if and normal if to work the same way.


Yes.


Some suggested ?? as an array access operator that suppresses the 
notice and
has 3 variants: A: nothing specified - uses null as default, B: has 
default
specified, C: returns X if index exists or Y if index doesn't exist. 
This
effectively solves the code duplication problem and is a shortcut for 
saying
the array index may or may not exist.


This only works if the test is made an isset() kind of test. If it
remains a boolean cast, it doesn't help much. (Or at least it doesn't
help me much.)

I also think it's a bit too blunt. In all but the simplest expressions
in the condition, desired notices could be silenced. I like the idea of
being able to specify exactly which array lookups should be silenced.

It also doesn't help the people

Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-13 Thread Ben Schmidt

I think these shortcuts could be really useful for array elements, but
for other variables I am really sceptical and I think they would do
more harm than good. Generally I do not really see any reason why a
variable should not be 'instanciated' before use.

So
+1 if this shortcut is implemented to only work for array elements.
-1 for any other variable type.


There are two issues here.

   1. Suppression of notice. I agree, it is best done only for array
   keys. It's not hard to initialise a variable with $var=null at the
   beginning of a code block to avoid such a notice, and that is the
   appropriate way to do it for variables.

   2. Offering a shortcut for the common idiom isset($x) ? $x : $y in
   line with the DRY design principle. A notice would never be emitted
   here in any case. The problem is that this idiom is still in wide use
   despite the shortcut ternary operator already provided, because an
   isset() check is different to a boolean cast.

Some thoughts:

   - Changing the existing behaviour of the ternary or shortcut ternary
 operator is a bad idea. Good arguments have been offered against
 it.

   - The actual intent of 2. is probably $x!==null ? $x : $y i.e. it's
 not about suppressing notices at all, but about offering a default
 value, and the idiom quite probably only uses isset() because it
 predated null in the language.

   - If we view 2. in this way, the two problems are independent, and it
 seems to me it would be best to solve them independently, rather
 than with a single operator.

So, I suggest:

   1. An array lookup mechanism that suppresses the notice for undefined
   keys. It would work the same as regular array index lookups except
   that the notice for undefined keys (and only for undefined keys)
   would not be generated (it would not just be hidden, but would never
   be even generated).

   2. A shortcut for $x!==null ? $x : $y.

This allows people to opt out of either feature if they don't want it,
and doesn't encourage poor coding by suppressing warnings for undefined
variables.

Arguing about syntax is then a second step. However, my views on this
are:

   1. Since we have @ meaning error-suppression already, why not reuse
   that symbol, in a location that is unambiguous? $array@[$key] would
   achieve this, right? It is localised to a single lookup, so can be as
   precise as the coder wants. E.g. one could do
   $array@[maybe-missing][expected]@[maybe-missing] and there's no
   ambiguity about what is meant. Nesting is likewise unambiguous, so in
   $array@[$lookups[key]] if key does not exist, we still get a
   notice.

   2. We just need a single symbol, probably with multiple characters.
   The key thing omitted by the shortcut is !==null so something that
   evokes that would be a good choice. Two possibilities are using
   something involving ? as in the ternary operator, or | as in the
   logical short-circuiting or operator. E.g. we could have $x ??: $y or
   $x ||| $y. However, both these somewhat imply either boolean tests or
   boolean results, which would be best to avoid. This is not about
   error suppression, so using @ would be unwise. Perhaps the best
   character to use is $ because $ somewhat represents a variable. So
   perhaps a good syntax would be $x $: $y. The $ somewhat evokes to me
   'use the variable if you can (it is not null)' and the : somewhat
   evokes 'otherwise', so I think it captures the meaning of the
   operator.

In combination (which some people probably want), this looks like
$array@[key] $: default

It's a bit different to what we're used to seeing, but the syntax is (1)
sensible and evocative of the right interpretation, and (2) not
misleading. I'd rather see something I'm unsure about and drives me back
to the docs than something that misleads me.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] proposed access modifier silent ... was: Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-11 Thread Ben Schmidt

I think another problem with using @ is that it is done by the caller,
not the callee, so it doesn't allow functions like issetor() to be
implemented in userland without expecting every caller to do pass the
variable while silencing errors.

I also don't think the inconvenience is restricted to arrays. I
frequently use the idiom isset(X)?X:Y with X simply being a variable.
It's not just about silencing a notice, but about providing an
alternative/default value.

If doing the suppression of undefined notices be better if the ? was put after the 
opening square bracket, thereby removing the ambiguity (which I think would be 
more troublesome than you think)? $array[?foo]


Ben.



On 11/04/11 6:10 PM, Hannes Landeholm wrote:

@ is not convenient since it turns off error reporting for all errors. I
don't know how many times I've silenced a notice and got a blank page in my
face as a thank you for accidentally silencing that fatal error too.

Silent is reserved for the purpose of the silence operator though @ so
using that as a keyword for something else would be confusing.


It just struck me that the ~real~ problem is that sometimes you want array
access that should define undefined indexes as being null (a good
placeholder for this purpose). How about (instead of the previously proposed
?? and isnotempty and whatnot) simply changing the array access syntax to
simply allow an optional ? operator at the end signaling that the
condition where the index isn't defined isn't unexpected?

For example:

$value = isset($arr[foo])? $arr[foo]: null;
$value = isset($arr[$foo])? $arr[$foo]: null;

would be replaced with: (respectively)

$value = $arr[foo?];
$value = $arr[$foo?];

it would also worked chained:

$value = $arr[foo?][bar][baz?]

(if [foo] doesn't exist value will be null.. if [foo] exists [foo][bar] is
expected to exist but [foo][bar][baz] may or may not exist... if not, value
will once again be null)

This way it would only apply to array access which was a +1 for some.

This could also be extended too replace null with something different (by
allowing an expression after the ? like null or foo . bar) but I
think careful use-case research should be done to determine if it's really
needed first...

I realize this partially collides with the use of ? so it would be more
difficult to implement but it's far from impossible.. it just requires a
little ahead-parsing in brackets [] to know if the ? is a ternary if or if
it's a not exists is not undefined operator (is the : missing or not?).
Otherwise ?? could simply be used instead or a completely different
operator...

~Hannes

On 11 April 2011 04:47, Stas Malyshevsmalys...@sugarcrm.com  wrote:


Hi!

  @.




Note however it does not exactly turn off the warning, only changes it to
not reported. It's still generated and can be picked up by handlers, for
example.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php






--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] proposed access modifier silent ... was: Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-11 Thread Ben Schmidt

If doing the suppression of undefined notices be better if the ? was put after 
the
opening square bracket, thereby removing the ambiguity (which I think would be
more troublesome than you think)? $array[?foo]


I suppose a non-array-specific version would be to put it after the $.

$?variable
$?array['foo']['bar']

I wonder if you could even use : with this syntax.

$?variable:default
$?array['foo']['bar']:default

Perhaps using it in function definitions is something to consider, too,
for a callee-specified undefined-notice-silencing mechanism.

function foo($?arg) {
}

Doesn't work for the variable arguments case, though, without resorting
to something IMHO ugly/hard-to-read-and-understand like:

function foo(?) {
}

It's another idea to throw in the mix, though.

I do think the 'silent' modifier that was the original suggestion in
this thread is worth further thought. It may well allow userland
functions to be developed, which might be a benefit.

I personally, though, think a modified ternary operator like the
proposed ??: or the syntax above, is better.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-08 Thread Ben Schmidt

On 9/04/11 12:45 AM, Martin Scotta wrote:

I just feels that !empty($arr['key']) or isset($arr['key']) do not express
the real meaning, instead I would choose to write array_key_exists('key',
$arr). It may be slower but it clearly express what I meant.


I don't like this. array_key_exists will return true for an array key
that exists but is set to null, which is rarely what is wanted (though
it sometimes is).

I agree that the variants with empty() aren't very good.

Just a single isset() variant seems like a good idea. I favour the ??:
syntax.

I liked the well-thought-out examples with assignment and chaining and
so on. For chaining, does associativity matter? (Too tired to figure it
out for myself right now!)

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-04-07 Thread Ben Schmidt

On 8/04/11 4:41 AM, Rasmus Lerdorf wrote:

On 4/7/11 2:30 PM, Rafael Dohms wrote:

On Thu, Mar 31, 2011 at 7:46 PM, Ben Schmidt
mail_ben_schm...@yahoo.com.au wrote:

On 1/04/11 3:29 AM, David Coallier wrote:


Hey there,

I've been working on a little patch that will allow variables ($1) in
a short-ternary operation to go through an implicit isset
(zend_do_isset_or_isempty) check so that the average use-case for the
short-ternary operator doesn't yield in a notice whenever the first
variable of the expression isn't set.

So the use-case I'm considering is the following:

?php
$list = array('name' = 'list');

echo $list['name'] ?: 'List not set.' . PHP_EOL;
echo $list['name-notset'] ?: 'List not set.' . PHP_EOL;
?

This example, which we all know, will result in a notice for the
second echo statement because the requested array-key doesn't actually
exist in the array.


I'm not familiar with the construct, but to be honest, I fail to see how
it is useful without the suppression of the notice. I mean, it's a
shorthand for isset($var)?$var:$something_else isn't it? That
presupposes that $var may not be set, but that you've accounted for that
fact, so don't want a notice about it. Obviously the isset() can only be
applied if the 'left hand side' is an lval, but I think it makes sense
to apply it whenever it is an lval.

So a big +1 from me.

Ben.



Its also a +1 for me, it would make the ternary operator much more
useful to me e remove lots of verbose code for handling arrays.


Well, it would change the semantics. And Ben, no, it isn't shorthand for an
isset() it is like writing (boolean)$var?$var:$something


Thanks for the clarification, Rasmus. That makes sense.

I still think the patch would be very useful, though I can also see how an 
argument could be made for keeping the warning. In my opinion, the case for 
removing the warning is stronger than for keeping it.


Ben.



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Optional $limit argument for debug_backtrace()

2011-04-04 Thread Ben Schmidt
Good idea. Have you considered how Xdebug does this kind of thing (through 
configuration directives, IIRC--I know it uses such things for var_dump) and 
whether that might suggest a better or more future-proof approach?


Ben.



On 5/04/11 1:22 AM, Sebastian Bergmann wrote:

https://gist.github.com/901579 is a patch against trunk that adds an
optional $limit argument to debug_backtrace() to limit the number of
frames returned.

Any thoughts?



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Adding a more logical string slicing function to PHP

2011-04-01 Thread Ben Schmidt

 string substr( string $string, int $start [, int $second [, int $flag =
 SUBSTR_LENGTH ]])

I think this just makes code ugly.

I think a new function with something like 'slice' in it is pretty unambiguous and 
unconfusing.


(I also like the current substr() semantics. Actually, I think 'slice' is the new 
kid on the block, and has only really come up in the last 10 years or so as web 
tech and scripting languages have grown. Before that, in C and BASIC and so on, 
semantics like substr() has were more common--at least for positive numbers. But 
that's neither here nor there.)


Ben.



On 1/04/11 6:01 PM, Alban LEROUX wrote:

Hi all,

I just come back on the first reflexion about adding a str_slice() function. As 
it
says before, using one method or the orther can really sucks in some cases, 
depending
what you are coding about.
So actually you mention there is two possibility :

- Keep all in the actual state. substr is allready quite cool but can suck in 
some
case.
- Add a new function and a create a possible confusion about the two method name
(like javascript), etc... bad idea.

In fact I see a third possibility, change the substr() function to handle the 
both
case. Here a simple proto :

string substr( string $string, int $start [, int $second [, int $flag =
SUBSTR_LENGTH ]])

with flags :
- SUBSTR_LENGTH (the default flags value corresponding to the actual behavior)
- SUBSTR_OFFSET (the new possibility to use an offset in third argument)

This keep the compatility with the actual substr() function, and enchance it, so
why not ?


On 2011-03-31 19:58:42 +0200, Martin Scotta said:


--20cf307d046c3ddbde049fcb0b8f

Content-Type: text/plain; charset=ISO-8859-1



I think it's time to stop thinking in terms of functions and move forward

to abstractions



$s1 = 'string';

$s1-contains($s2);



$s1-indexOf($s2) === strpos($s1, $s2);



Why can't the strings be exposed as pseudo-objects ? users can choose to use

them as a regular strings or by calling methods on it.



Martin Scotta





On Thu, Mar 31, 2011 at 12:52 PM, Rasmus Lerdorf ras...@lerdorf.com wrote:



 On 03/31/2011 08:45 AM, Philip Olson wrote:



  - Intuitive name



 Argh! Everyone should be forced to learn a bit of C. Like many PHP

 functions, the name and argument order is right out of libc. If you type

 man strstr at your (non-Windows) prompt you get a nice little

 description of what it does.



 -Rasmus





--20cf307d046c3ddbde049fcb0b8f--






--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implicit isset/isempty check on short-ternary operator

2011-03-31 Thread Ben Schmidt

On 1/04/11 3:29 AM, David Coallier wrote:

Hey there,

I've been working on a little patch that will allow variables ($1) in
a short-ternary operation to go through an implicit isset
(zend_do_isset_or_isempty) check so that the average use-case for the
short-ternary operator doesn't yield in a notice whenever the first
variable of the expression isn't set.

So the use-case I'm considering is the following:

?php
 $list = array('name' =  'list');

 echo $list['name'] ?: 'List not set.' . PHP_EOL;
 echo $list['name-notset'] ?: 'List not set.' . PHP_EOL;
?

This example, which we all know, will result in a notice for the
second echo statement because the requested array-key doesn't actually
exist in the array.


I'm not familiar with the construct, but to be honest, I fail to see how
it is useful without the suppression of the notice. I mean, it's a
shorthand for isset($var)?$var:$something_else isn't it? That
presupposes that $var may not be set, but that you've accounted for that
fact, so don't want a notice about it. Obviously the isset() can only be
applied if the 'left hand side' is an lval, but I think it makes sense
to apply it whenever it is an lval.

So a big +1 from me.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] preg_replace does not replace all occurrences

2011-03-15 Thread Ben Schmidt

static $re = '/(^|[^])\'/';


Did no one see why the regex was wrong?


I saw what the regex was. I didn't think like you that it was 'wrong'.

Once you unescape the characters in the PHP single-quoted string above
(where two backslashes count as one, and backslash-quote counts as a
quote), the actual pattern that reaches the preg_replace function is:

   /(^|[^\\])'/


RegexBuddy (a windows app) explains regexes VERY VERY well.


What kind of patterns? Does it support PCRE ones?


The important bit (where the problem lies with regard to the regex) is
...

Match a single character NOT present in the list below «[^]»
 A \ character «\\»
 A \ character «\\»


This is not the case.

1. As above, the pattern reaching preg_replace is /(^|[^\\])'/

2. PCRE, unlike many other regular expression implementations, allows
backslash-escaping inside character classes (square brackets). So the
doubled backslash only actually counts as a single backslash character
to be excluded from the set of characters the atom will match.

There is no error here. (And even if there were two backslashes being
excluded, of course, it wouldn't hurt anything or change the meaning of
the pattern.)


The issue is the word _single_.


I don't think anybody thought otherwise.

The problem was that, to a casual observer, the pattern seems to mean a
quote which doesn't already have a backslash before it. I believe this
was its intent. (And the replacement added the 'missing' backslash.)

But the pattern doesn't mean that. It actually means a character which
isn't a backslash, followed by a quote. This is subtly different.

And it's most noticeable when two quotes follow each other in the
subject string. In

   str''str

first the pattern matches r' (non-backslash followed by quote), and
then it keeps searching from that point, i.e. it searches 'str. Since
this isn't the beginning of the string, and there is no quote following
a non-backslash character, there are no further matches.

Now, here is a pattern which actually means a quote which doesn't
already have a backslash before it which is achieved by means of a
lookbehind assertion, which, even when searching the string after the
first match, 'str, still 'looks back' on the earlier part of the
string to recognise the second quote is not preceded by a backslash and
match a second time:

   /(^|(?!\\))'/

As a PHP single-quoted string this is:

   '/(^|(?!))\'/'

Hope this helps,

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] preg_replace does not replace all occurrences

2011-03-15 Thread Ben Schmidt

Now, here is a pattern which actually means a quote which doesn't
already have a backslash before it which is achieved by means of a
lookbehind assertion, which, even when searching the string after the
first match, 'str, still 'looks back' on the earlier part of the
string to recognise the second quote is not preceded by a backslash and
match a second time:

/(^|(?!\\))'/

As a PHP single-quoted string this is:

'/(^|(?!))\'/'


And I should mention, as Martin did, that this actually isn't a good
idea. There are better/safer ways to escape quotes. In particular,
consider how this subject string

   str\\'; delete from users;

will not have the quote escaped, because it is preceded by *two*
backslashes. To match more carefully, you have to be careful to 'eat
backslashes in pairs'. Someone gave a pattern that attempted to do
something like that in an earlier post, too.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] preg_replace does not replace all occurrences

2011-03-14 Thread Ben Schmidt

On 15/03/11 2:18 AM, Martin Scotta wrote:

I chose the simplest example to show the preg_replace behavior,


You've GOT to be kidding. The SIMPLEST?!

How about an example that doesn't require escaping ALL the interesting
characters involved?

Here's a modified version that I think it quite a bit simpler:

?php
function test($str) {
   static $re = '/(^|[^a])b/';
   static $change = '$1ab';

   echo $str, PHP_EOL; // input
   echo preg_replace($re, $change, $str), PHP_EOL, PHP_EOL; // output
}

test(str bb str); // bug?
test(str abab str); // ok
test(b str b); // ok
test(ab str ab); // ok
?

The way I interpret it, it should put an 'a' before every 'b' that is
not already preceded by an 'a'.

But the buggy case gives 'str abb str' rather than the expected
'str abab str'.

It does look like a bug to me.

Ben.




there are
better (and safer) ways to scape slash characters.
Anyways, *is this the expected preg_replace behavior?*

  Martin

?php
function test($str) {
 static $re = '/(^|[^])\'/';
 static $change = '$1\\\'';

 echo $str, PHP_EOL,
 preg_replace($re, $change, $str), PHP_EOL, PHP_EOL;
}

test(str '' str); // bug?
test(str \\'\\' str); // ok
test('str'); // ok
test(\'str\'); // ok


Expected:

str '' str
str \'\' str

str \'\' str
str \'\' str

'str'
\'str\'

\'str\'
\'str\'


Result:

str '' str
str \'' str

str \'\' str
str \'\' str

'str'
\'str\'

\'str\'
\'str\'


  Martin Scotta



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] preg_replace does not replace all occurrences

2011-03-14 Thread Ben Schmidt

On 15/03/11 5:38 AM, Ben Schmidt wrote:

On 15/03/11 2:18 AM, Martin Scotta wrote:

I chose the simplest example to show the preg_replace behavior,


You've GOT to be kidding. The SIMPLEST?!

How about an example that doesn't require escaping ALL the interesting
characters involved?

Here's a modified version that I think it quite a bit simpler:

?php
function test($str) {
static $re = '/(^|[^a])b/';
static $change = '$1ab';

echo $str, PHP_EOL; // input
echo preg_replace($re, $change, $str), PHP_EOL, PHP_EOL; // output
}

test(str bb str); // bug?
test(str abab str); // ok
test(b str b); // ok
test(ab str ab); // ok
?

The way I interpret it, it should put an 'a' before every 'b' that is
not already preceded by an 'a'.

But the buggy case gives 'str abb str' rather than the expected
'str abab str'.

It does look like a bug to me.


Actually, no it doesn't.

The behaviour is correct.

Matches cannot overlap. Since the character preceding 'b' is part of the
match, there is only one match in the string 'str bb str'. The match is
' b'. After that match, the

You actually want an assertion. I think this:

static $re = '/(^|(?!a))b/';

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] native php annotations

2011-03-13 Thread Ben Schmidt

On 14/03/11 8:47 AM, Marcelo Gornstein wrote:

it has already been discussed with length. Please take a look at:

http://wiki.php.net/rfc/annotations

Thank you for the link. That is actually pretty much what I intended
to do. The only difference with my own version lies in the possibility
to annotate method parameters (very useful in many cases when using an
IoC/DI container). So that would be my 2 cents there.


I haven't read the RFC, but what you suggested in your earlier email
looked good to me, and I like the idea, so I'd be in favour of doing
something. (I'm new here, too, and not a core dev or anything, so my
opinion doesn't and shouldn't carry much weight, but there it is.)

Ben.



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-23 Thread Ben Schmidt

public function Killjoy(MyEnum $x)


What would be the purpose of such code? What would it do if 5 is passed as
$x?


Are you suggesting this as an enum member function, or just a regular
function in any old class?

If 'in an enum', I think by analogy with the stuff somebody linked to on
the MS site to do with C#, it can only ever be invoked by doing
EnumConstant.Killjoy(); and EnumConstant is automatically passed as an
argument to the function--you could never pass 5. I think this is a bit
crazy, though, blurring the lines between enums and classes way too
much, and not a good idea for PHP.

If just 'any old function', there are two possibilities: if 5 is passed,
the type hint recognises that 5 is not of the MyEnum type, so fails; you
would have to explicitly cast 5 as a MyEnum when calling the function to
make it work; or the other possibility is that Killjoy attempts a cast
and only fails if 5 cannot be cast to the enum (I prefer this way). In
both cases, though, that would not be expected to be the usual way to
use the function: you would usually be expected to pass in a true enum
constant of the MyEnum type.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-23 Thread Ben Schmidt

Are you suggesting this as an enum member function, or just a regular
function in any old class?


Enum member funcion? How much it should be like a class before you
call it a class?


Exactly. It's crazy. If you want a 'member function' use a class, not an
enum.


use the function: you would usually be expected to pass in a true enum
constant of the MyEnum type.


That works wonders in dynamic languages, without any means of really
ensuring it.


No, I believe you can ensure it, and you can even ensure it efficiently.
I outlined this in a more lengthy email earlier today. I was against
type hinting until I realised that yes, it could work, and work
efficiently.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Extensions to traits

2011-02-23 Thread Ben Schmidt

On 13/02/11 9:15 PM, André Rømcke wrote:

On Thu, Feb 10, 2011 at 6:25 PM, Ben Schmidt
mail_ben_schm...@yahoo.com.auwrote:


On 11/02/11 3:37 AM, Philip Olson wrote:


You now have rights to the wiki rfc namespace.



Thanks a lot, Philip.

I have now made an RFC based on the most recent discussions:

http://wiki.php.net/rfc/traitsmodifications

I think this is a more solid proposal than my original one, and I hope
we can continue to discuss it and agree to the extent that it's worth
starting an implementation.

Please read it and comment whenever you can find some time, guys!




As for your first example:


trait T {
public function foo() {
   echohttp://www.php.net/echo  T;
}}class C {
use T;
public function foo() {
   echohttp://www.php.net/echo  C;
}}


I think it would sometimes be desirable to allow this, for instance when a
trait has been updated in a framework to adapt to what has become common
practice in classes that uses it in the wild.
( I assume you already get error if function signature is different like in
inheritance? )

So to allow both cases, what about letting people use the final keyword on
functions to signal functions that can not be re declared without alias. Or
better, add a new keyword since final should mean final.


I don't mind that idea all that much, but perhaps doing the reverse
makes more sense: allowing a trait author to add a keyword to methods
which they intend and expect class authors to shadow. This means the
status quo is leaning towards stability, not breakages. Perhaps we could
reuse the 'default' keyword for this? That would indicate that the trait
has provided a default implementation of this method, but expects the
class author may well provide a more specialised implementation. Best
practice would then dictate that a responsible trait author should only
provide a default method for methods that were previously abstract
methods of the trait, so things wouldn't break, but traits can still
adapt to common practice, as you say.

So then this would generate an error, which could be resolved with an
insteadof in the use block:

trait T {
public function foo() {
   echo T;
}
}
class C {
use T;
public function foo() {
   echo C;
}
}

But this would not:

trait T {
default public function foo() {
   echo T;
}
}
class C {
use T;
public function foo() {
   echo C;
}
}

How does that sound?

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Extensions to traits

2011-02-23 Thread Ben Schmidt

That might seem odd but it's not inheritance.


Yeah. And that's my main concern with it. It seems like inheritance (and
is described like inheritance in the RFC at present--which is a
documentation issue that will need to be addressed in the manual
eventually), but it isn't. I feel it should be one or the other: either
have full inheritance semantics, or have full conflict-resolution
semantics like when trait methods conflict, at least by default. I think
the latter is better.

I'm really warming to the idea of using 'default' as I proposed in my
last email, though, as essentially doing what André suggested 'in
reverse'--i.e. a 'non-final' marker.

Ben.





--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Extensions to traits

2011-02-23 Thread Ben Schmidt

http://wiki.php.net/rfc/traitsmodifications



Some thoughts:

a) Class method conflict with trait

Class implementation always wins I feel is the right way to think about
traits.

But 'abstract' already has special meaning, so maybe a keyword like 'final'
could also do something special.


André had the same kinds of feelings. I feel marking 'non-final' would
be better, and suggest using 'default' for this purpose. See my earlier
email for more details and reasoning.


b) Support for 'non-breakable traits'

  - Add trait-local scope

Really like the idea and how this could make traits less fragile.
e.g.
trait Foo {
   trait $bar;
   public $bar;
}

Could change the syntax to:
trait Foo {
   var $bar = 'visibleByTrait'; // variable private to the trait --
zend_mangle_property_name('#Foo {NULL} bar')
   public $bar = 'visibleByClass';  // variable public to the class it gets
composed in
}

class Test {
   use Foo;
}

$t = new Test;
echo $t-bar; // 'visibleByClass'

Seems like it could allow traits to have their own independent state
(private properties), internally ~ zend_mangle_property_name('#' trait name
{NULL} prop name).

Small note: is there a plan to drop the T_VAR token?

Any objections, concerns, more thoughts on the concept?


I think it needs to work for methods as well as properties, so think the
'trait' keyword is better than the 'var' keyword for that reason. It
would seem strange prefixing a method with 'var'.


c)  Extend 'use' syntax

Didn't quite understand, will read again.
Have you thought about how this could affect the reflection api and
documentation?


Yes, I had thought about it a bit. Now I've thought a bit further.

When extended syntax is just moving class and trait methods around
(essentially either duplicating them or omitting them), the reflection
API should just work on the results of that movement. I presume that is
what happens with traits.

When extended syntax is generating forwarding functions, I expect the
reflection API to return details of those forwarding functions. It can't
do anything else, as due to PHP's dynamic nature, the functions being
forwarded to are not immutable. I would document it as a forwarding
function generation mechanism, too, so confusion is avoided.

Having thought about it a bit further now, though, the reflection API is
arguably a bit useless in this case. Perhaps to mitigate this, a new
method could be added to ReflectionMethod to find details of the target
of a forwarding method for a particular object (at the particular time
the method is invoked).

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-23 Thread Ben Schmidt

why not supporting methods for enum values?
developers will need that, and by providing type hinting, they will just
create the logic somewhere else...


why would developers need this? can you elaborate with some real-life
scenario?
I thought enums are just strong-typed constants


I think this way, too.

Strings are not objects in PHP, and you can't call methods on them. It
makes sense for enum constants to behave the same way in PHP and not
have callable methods.


Think on any finite set of elements that cannot be represented with integers
because they don't hold enough data... or because the repeated values.

An extremely example could be the Periodic Table, finite set of elements,
where each element holds a lot of information.

function print_element(Element $e) {
   echo $e-weight(), PHP_EOL,
$e-density(), PHP_EOL,
$e-protons(), PHP_EOL,
$e-neutrons();
}
print_element(Element:Hydrogen);
print_element(Element:Argon);
print_element(Element:Iron);

How do you implement this with just string=integer define or constants?
so you need classes..  do they fit well? I don't think so

$h = new Hydrogen(); // What would mean this?
$h = Element::Hydrogen(); // probably with a static method
$h = Element::Hydrogen; // class constant? lack of objects support


I think this is good enough:

abstract class Element {
   enum {
  Hydrogen,
  Argon,
  Iron
   }
   public static function weight(Element $e) {
  ...
   }
   ...
}
function print_element(Element $e) {
   echo Element::weight($e), PHP_EOL,
Element::density($e), PHP_EOL,
Element::protons($e), PHP_EOL,
Element::neutrons($e);
}
print_element(Element::Hydrogen);
print_element(Element::Argon);
print_element(Element::Iron);

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-23 Thread Ben Schmidt

You're right, my example was broken with regard to type hinting. Should
have been more like:

abstract class Element {
 enum Type {
Hydrogen,
Argon,
Iron
 }
 public static function weight(Element::Type $e) {
...
 }
 ...
}
function print_element(Element::Type $e) {
 echo Element::weight($e), PHP_EOL,
  Element::density($e), PHP_EOL,
  Element::protons($e), PHP_EOL,
  Element::neutrons($e);
}
print_element(Element::Hydrogen);
print_element(Element::Argon);
print_element(Element::Iron);

which I agree is quite a bit more ugly.

So maybe member methods are useful after all. However, I think they need
to be implemented differently to the 'extension method' mechanism of C#.
In PHP, we could simply require them to be static methods, and set $this
to the enum constant value (strongly typed) when they are called.

So I think all your recommendations are good, as long as.

- We take care to implement it efficiently, so enum comparisons etc. are
  pointer comparisons, not string or other comparisons.
- We are careful to restrict enum member functions appropriately so
  enums don't turn into full-blown classes.

Ben.



On 24/02/11 2:34 AM, Jarrod Nettles wrote:

I don't think that your implementation will work as it would require
an entire re-imagining of type hinting and/or of classes. In your
example, any method that type hinted against Element would be
expecting an instance of the abstract class, Element. There's no way
to differentiate between the two.

Another thing to consider: suppose another class extends your abstract
class Element and defines its own enum? Which takes precedence? Do
the two merge, overwrite, etc? I think that would end up causing more
problems than it's worth.

Based on our current discussion and recommendations, here's how I
would say we define a PHP enum:

1. An enumeration has a name, whether outside a class or inside a class.
2. The names of the constants are strings.
3. Values can be integrals or strings. No complex types or arrays.
4. Can be namespaced like any class, function, or interface.
5. Can have member methods, must be declared as static since an enum cannot be 
instantiated.
6. Parameters can be type hinted against enums. For consistency, in the event 
of invalid arguments we should probably stay in line with what happens when a 
type hint for a class is broken.



-Original Message-
From: Ben Schmidt [mailto:mail_ben_schm...@yahoo.com.au]
Sent: Wednesday, February 23, 2011 9:01 AM
To: Martin Scotta
Cc: Alexey Zakhlestin; Stas Malyshev; Jarrod Nettles; internals@lists.php.net
Subject: Re: [PHP-DEV] Re: Clarification on the Enum language structure

I think this is good enough:

abstract class Element {
 enum {
Hydrogen,
Argon,
Iron
 }
 public static function weight(Element $e) {
...
 }
 ...
}
function print_element(Element $e) {
 echo Element::weight($e), PHP_EOL,
  Element::density($e), PHP_EOL,
  Element::protons($e), PHP_EOL,
  Element::neutrons($e);
}
print_element(Element::Hydrogen);
print_element(Element::Argon);
print_element(Element::Iron);

Ben.



html
body
Jarrod Nettles Application Developer - Technology INCCRRA p 309.829.5327 - f 
309.828.1808 This e-mail message may contain privileged or confidential 
information. If you are not the intended recipient, you may not disclose, use, 
disseminate, distribute, copy
  or rely upon this message or attachment in any way. If you received this 
e-mail message in error, please return by forwarding the message and its 
attachments to the sender. INCCRRA does not accept liability for any errors, 
omissions, corruption or virus in
  the contents of this message or any attachments that arises as a result of 
e-mail transmission. Please consider your environmental responsibility before 
printing this e-mail
/body
/html



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-23 Thread Ben Schmidt

On 24/02/11 8:33 AM, Stas Malyshev wrote:

Hi!


use the function: you would usually be expected to pass in a true enum
constant of the MyEnum type.


That works wonders in dynamic languages, without any means of really
ensuring it.


No, I believe you can ensure it, and you can even ensure it efficiently.


I don't see how you can do it without typing variables and functions
and doing static type control.


You can do it like this. When an enum is defined:

- internally create a class to represent the enum; flag it as an enum
  class, not a regular class; this restricts any PHP code from
  attempting to access properties of the class, instantiate it, etc..
- internally instantiate an object of the class for every enum constant;
  each object contains a member with the integer/string representation
  of the constant.
- internally create a static array in the class, associating every enum
  value to its instantiated object.

When an enum is type-hinted, you just check the value is internally an
object of the enum class.

When cast to integer or string, or serialising, or used in a context
where an integer or string is required, simply use the scalar value in
the enum object. Perhaps do this whenever passed to a built-in function,
too, unless explicitly type-hinted, or a special case such as
call_user_func where the enum is going to work its way back into PHP
code, merely as a convenience to avoid needing to change a lot of C code
to check and cast enums.

When cast to enum, or deserialising, look up the relevant integer or
string in the internal enum class's array to efficiently get the
strongly typed enum value.

When comparing enums for equality, compare pointers only. There will
always be exactly one internal object for each enum constant, so this
will work.

When comparing enums for ordering (less than, greater than), look up the
scalar values and compare them.


Even then - what if you read values from config file or database?
Would you have 50-item switch to match config values to typed Enum
values?


You'd just cast it to the enum type, at which point PHP would look up
the enum value in the internal array in the enum class to efficiently
retrieve the relevant strongly typed enum constant.

I also suggest when type-hinting, if the type is integer or string where
an enum is expected, PHP attempts a cast before failing, to make this
more convenient.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-23 Thread Ben Schmidt

I also suggest when type-hinting, if the type is integer or string where
an enum is expected, PHP attempts a cast before failing, to make this
more convenient.


O, and if this cast (or any cast to enum) fails, IMHO, it should replace
it with null. When type-hinting, this means that if null is an
acceptable value, execution can continue. If not, error, same as if
something of a non-scalar non-matching type is passed, consistent with
object type hints.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-23 Thread Ben Schmidt

Don't your arguments work equally well against type hinting for objects?
You have the same problems: if you screw something up in user code and
pass the wrong type, it fails at runtime. You also get 'random' failures
if you deserialise/read from config an object whose internal type
changed since it was serialised if you don't validate this (which you
usually don't). Yet we have object type hinting, because it is useful,
and it works OK most of the time. I think the same for enum type
hinting.

Ben.



On 24/02/11 1:00 PM, Stas Malyshev wrote:

Hi!


You can do it like this. When an enum is defined:


I'm not talking about implementation in the code of PHP engine. I'm talking 
about
writing code with these things that wouldn't produce fatal errors in random 
places
without you being able to prevent it and without checking before each function
call. Compiled languages deal with it easily because they check these things on
compile - if you try to send int variable where BlahBlah type is expected, the
compiler bails out and you know it's a problem. Dynamic languages don't work 
that
way.


You'd just cast it to the enum type, at which point PHP would look up
the enum value in the internal array in the enum class to efficiently
retrieve the relevant strongly typed enum constant.


But the procedure loading the configs probably has no idea about your enums - 
for
it it's just nmumbers. So you'd probably have to take the cast down close to the
actual call. At which time you could as well done the proper check and handle it
in an application-specific way.


I also suggest when type-hinting, if the type is integer or string where
an enum is expected, PHP attempts a cast before failing, to make this
more convenient.


Strict typing is not robust unless you can ensure your variables and method
returns have required types - either using compiler or manually checking.
Converting helps a little here but still you're putting into the language
something that is best handled on user-level since the language doesn't have
enough information to handle it.





--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-22 Thread Ben Schmidt
Can't remember whether I answered this clearly. I don't think type hinting is 
worth the implementation overhead (loss of efficiency) it would require.


Ben.



On 23/02/11 1:11 AM, Jarrod Nettles wrote:

Apologies - I wasn't suggesting we implement extension methods. I was simply 
changing my mind and agreeing with the earlier point that methods for enums can 
be useful.

What is everyone's opinion on enums as type hinted parameters? Being able to 
do...

public function Killjoy(MyEnum $x)

-Original Message-
From: Ben Schmidt [mailto:mail_ben_schm...@yahoo.com.au]
Sent: Friday, February 18, 2011 10:28 PM
To: Jarrod Nettles
Cc: Martin Scotta; Thomas Gutbier; internals@lists.php.net; Stas Malyshev
Subject: Re: [PHP-DEV] Re: Clarification on the Enum language structure


I did some research on methods in enums and discovered that there is
some usefulness to the idea - I wouldn't go so far as to say that they
would be needed, but C#, for example, allows you to create extension
methods for enums and MSDN has a decent real-world example of its use.

http://msdn.microsoft.com/en-us/library/bb383974.aspx


It's a pretty big new concept that would need to be introduced if this
was desired: extension methods.

I think it's overkill myself. Something like this is fine:

class Grade {
 enum {
A_PLUS,
A,
B_PLUS,
B,
...,
FAIL,
NOT_AVAILABLE,
 }
 public static function passing($grade) {
return $grade=self::D;
 }
}
$grade=Grade::B;
echo Grade::passing($grade)?passing:not passing;

Having extension methods would also make enums much less efficient, as
they would have to be stored as objects so their exact enum type could
be determined at runtime if calling a method.

I guess supporting type hinting properly also requires this, if that's
desired, though. But I personally think something simple, much closer to
the existing RFC, is fine. There isn't much benefit in type hinting--it
could catch some programmer errors, but that's it--a small debugging
tool. If it doesn't actually enable overloading (in the C++ sense) or
something like that, it's not really an advantage.

Regarding named enums, this could just be a shortcut for an enum in a
class:

enum Grade {
 A_PLUS,
 A,
 ...
}

is shorthand for

class Grade {
 enum {
A_PLUS,
A,
...
 }
}

so you then do Grade::A etc.. You could disallow named enums in classes,
or they could be named purely to make code self-documenting.


Enum type in the database is totally different because it's a
constraint, not an alias to some underlying piece of data like enums
in many programming languages. I think enforcing such constraint in
PHP would be quite complicated.


No, I think enums in MySQL at least are true types, not just
constraints--they are internally stored as integers and various
optimisations are done with queries based on this.

I agree strings as values do have the advantage of more robust (albeit
less efficient) serialisation, including interacting with databases such
as MySQL with enum types. So I think this would be worth allowing, but
no more.

So I would suggest having enum value allocation work like array indexes.
If you don't supply a value, it uses the next unused integer. But you
may alternatively supply an integer or a string. So, doing

enum {
 FIRST,
 SECOND,
 THIRD,
 LAST = 'last'
}

would be much like doing

$enum[]='FIRST';
$enum[]='SECOND';
$enum[]='THIRD';
$enum['last']='LAST';

in that 0, 1, 2 and 'last' are used.

There's a few more cents from me. :-)

Ben.
html
body
Jarrod Nettles Application Developer - Technology INCCRRA p 309.829.5327 - f 
309.828.1808 This e-mail message may contain privileged or confidential 
information. If you are not the intended recipient, you may not disclose, use, 
disseminate, distribute, copy
  or rely upon this message or attachment in any way. If you received this 
e-mail message in error, please return by forwarding the message and its 
attachments to the sender. INCCRRA does not accept liability for any errors, 
omissions, corruption or virus in
  the contents of this message or any attachments that arises as a result of 
e-mail transmission. Please consider your environmental responsibility before 
printing this e-mail
/body
/html



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-22 Thread Ben Schmidt

After a little more thought, I'm doing a U-turn. I agree, type hinting is a 
goer.

My previous thinking had been tainted by the talk of classes, and there is 
potentially a lot of overhead in making an enum behave like a class.


However, there is very little overhead in supporting type hinting. All the enum 
constants can be created as static immutable objects when the enum is declared, 
and any time an enum constant is encountered, or a value is cast to the enum, a 
hash table can be used to look up the appropriate object and a pointer set to it. 
The objects are immutable, so never need to be cloned, garbage collected, 
anything. Comparisons are even cheaper than with strings, as they can just be 
pointer comparisons. Type hinting just checks an attribute of the object and is 
also very fast. Memory use is negligible.


Since it can be so efficient, I'm all for it.

Ben.



On 23/02/11 4:03 AM, Jarrod Nettles wrote:

I would argue that type hinting here is worth the overhead. Here’s my support 
for type hints:


1.  They are optional – people truly concerned about squeezing every last 
drop of performance can opt to not use them and are probably using an 
accelerator anyway which will iron out such problems.

2.  Programmer productivity should be just as large of a concern as 
performance. When it comes down to it the programmer is usually the most 
expensive resource in the software development lifecycle and performance issues 
can be solved with extra RAM or another server for a pittance.

3.  Better IDE support. Having type hints right in the method makes it 
easier for the IDEs to adapt and become more intelligent which increase 
usability and programmer performance which increases the number of people 
willing to use PHP.

4.  Better code readability. This is in line with point #2 – when I jump 
over to look at a method definition it will be 10x faster for me to see that 
particular parameter is an enum rather than having to search through the code 
to see that $cheese actually represents an enum of type Cheese.


From: Martin Scotta [mailto:martinsco...@gmail.com]
Sent: Tuesday, February 22, 2011 10:25 AM
To: Ben Schmidt
Cc: Jarrod Nettles; Thomas Gutbier; internals@lists.php.net; Stas Malyshev
Subject: Re: [PHP-DEV] Re: Clarification on the Enum language structure

I just don't get why no type hinting, I thought that was one of the big points

so what are the purposes of the new enums?
could you provide an example (a little snippet) of  the usage of them?

On Tue, Feb 22, 2011 at 11:15 AM, Ben 
Schmidtmail_ben_schm...@yahoo.com.aumailto:mail_ben_schm...@yahoo.com.au  
wrote:
Can't remember whether I answered this clearly. I don't think type hinting is 
worth the implementation overhead (loss of efficiency) it would require.

Ben.



  Martin Scotta


On 23/02/11 1:11 AM, Jarrod Nettles wrote:
Apologies - I wasn't suggesting we implement extension methods. I was simply 
changing my mind and agreeing with the earlier point that methods for enums can 
be useful.

What is everyone's opinion on enums as type hinted parameters? Being able to 
do...

public function Killjoy(MyEnum $x)

-Original Message-
From: Ben Schmidt 
[mailto:mail_ben_schm...@yahoo.com.aumailto:mail_ben_schm...@yahoo.com.au]
Sent: Friday, February 18, 2011 10:28 PM
To: Jarrod Nettles
Cc: Martin Scotta; Thomas Gutbier; 
internals@lists.php.netmailto:internals@lists.php.net; Stas Malyshev
Subject: Re: [PHP-DEV] Re: Clarification on the Enum language structure
I did some research on methods in enums and discovered that there is
some usefulness to the idea - I wouldn't go so far as to say that they
would be needed, but C#, for example, allows you to create extension
methods for enums and MSDN has a decent real-world example of its use.

http://msdn.microsoft.com/en-us/library/bb383974.aspx

It's a pretty big new concept that would need to be introduced if this
was desired: extension methods.

I think it's overkill myself. Something like this is fine:

class Grade {
 enum {
A_PLUS,
A,
B_PLUS,
B,
...,
FAIL,
NOT_AVAILABLE,
 }
 public static function passing($grade) {
return $grade=self::D;
 }
}
$grade=Grade::B;
echo Grade::passing($grade)?passing:not passing;

Having extension methods would also make enums much less efficient, as
they would have to be stored as objects so their exact enum type could
be determined at runtime if calling a method.

I guess supporting type hinting properly also requires this, if that's
desired, though. But I personally think something simple, much closer to
the existing RFC, is fine. There isn't much benefit in type hinting--it
could catch some programmer errors, but that's it--a small debugging
tool. If it doesn't actually enable overloading (in the C++ sense) or
something like that, it's not really an advantage.

Regarding named enums, this could just be a shortcut for an enum in a
class:

enum Grade

Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-18 Thread Ben Schmidt

I did some research on methods in enums and discovered that there is
some usefulness to the idea - I wouldn't go so far as to say that they
would be needed, but C#, for example, allows you to create extension
methods for enums and MSDN has a decent real-world example of its use.

http://msdn.microsoft.com/en-us/library/bb383974.aspx


It's a pretty big new concept that would need to be introduced if this
was desired: extension methods.

I think it's overkill myself. Something like this is fine:

class Grade {
   enum {
  A_PLUS,
  A,
  B_PLUS,
  B,
  ...,
  FAIL,
  NOT_AVAILABLE,
   }
   public static function passing($grade) {
  return $grade=self::D;
   }
}
$grade=Grade::B;
echo Grade::passing($grade)?passing:not passing;

Having extension methods would also make enums much less efficient, as
they would have to be stored as objects so their exact enum type could
be determined at runtime if calling a method.

I guess supporting type hinting properly also requires this, if that's
desired, though. But I personally think something simple, much closer to
the existing RFC, is fine. There isn't much benefit in type hinting--it
could catch some programmer errors, but that's it--a small debugging
tool. If it doesn't actually enable overloading (in the C++ sense) or
something like that, it's not really an advantage.

Regarding named enums, this could just be a shortcut for an enum in a
class:

enum Grade {
   A_PLUS,
   A,
   ...
}

is shorthand for

class Grade {
   enum {
  A_PLUS,
  A,
  ...
   }
}

so you then do Grade::A etc.. You could disallow named enums in classes,
or they could be named purely to make code self-documenting.


Enum type in the database is totally different because it's a
constraint, not an alias to some underlying piece of data like enums
in many programming languages. I think enforcing such constraint in
PHP would be quite complicated.


No, I think enums in MySQL at least are true types, not just
constraints--they are internally stored as integers and various
optimisations are done with queries based on this.

I agree strings as values do have the advantage of more robust (albeit
less efficient) serialisation, including interacting with databases such
as MySQL with enum types. So I think this would be worth allowing, but
no more.

So I would suggest having enum value allocation work like array indexes.
If you don't supply a value, it uses the next unused integer. But you
may alternatively supply an integer or a string. So, doing

enum {
   FIRST,
   SECOND,
   THIRD,
   LAST = 'last'
}

would be much like doing

$enum[]='FIRST';
$enum[]='SECOND';
$enum[]='THIRD';
$enum['last']='LAST';

in that 0, 1, 2 and 'last' are used.

There's a few more cents from me. :-)

Ben.

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-18 Thread Ben Schmidt
, not the string
representations. So it's really no brainer to make enumerations to
work transparently with MySQL.

2011/2/18 Jarrod Nettlesjnett...@inccrra.org:

I did some research on methods in enums and discovered that there is

some usefulness to the idea - I wouldn't go so far as to say that they would
be needed, but C#, for example, allows you to create extension methods for
enums and MSDN has a decent real-world example of its use.


http://msdn.microsoft.com/en-us/library/bb383974.aspx

I still don't understand why we would need string values (or any other

non-integral type) but like you said Ben - if you need something like that
you're not using the right datatype. Build a class. Here's my reasoning for
enum values.


enum Wood{
OAK,
ASH,
WILLOW,
GOPHER
}

There's nothing in there that would necessitate needing a string value

and really, if you need a string value, pass in a string as your parameter!
Enumerations should be used to represent a set of data where the value
itself isn't so important, it’s the consistency of the value that's
important. It’s the fact that I've chosen gopher wood and I know that even
though Wood::GOPHER really means 3, I don't have to remember what 3
represents because I can specifically type that I want gopher.



-Original Message-
From: Ben Schmidt [mailto:mail_ben_schm...@yahoo.com.au]
Sent: Thursday, February 17, 2011 4:52 PM
To: Martin Scotta
Cc: Jarrod Nettles; Thomas Gutbier; internals@lists.php.net
Subject: Re: [PHP-DEV] Re: Clarification on the Enum language structure


Also, I feel like it should be restricted to integral types only, and
defaults to a zero-based incrementing integer. This is more in line

with

other programming languages that already implement enums and will

present

expected behavior for people moving over to PHP.


for me that's a plain old interpretation of constants.
constant values were only integer values because of their

implementation,

nowadays they could be anything you want, int, float, string and even
objects.


I partially agree with that.

I'm going to be a bit extreme here, but here's a thought:

An enum is something you use conceptually for a set of constant values
which aren't related in a numerical or other fashion (where another type
would make more sense). In an enum, the only meaning of a constant is
the meaning expressed in that constant's name.

So you shouldn't want to use ints, floats, strings, certainly not
objects, for enum values. If you feel yourself wanting to do this, an
enum is not the right datatype for your purpose--you should be using one
of those other types instead, possibly with a very few defined constants
for commonly-used or 'magic' values.

The issue, then, of what type underlies an enum is mostly to do with
internal implementation, and more importantly, serialisation. Integers
are the simplest and most obvious way to do this. But short strings,
particularly string representations of the enum's symbols, could be a
nice way to make serialised data more readable, and less fragile (e.g.
if values are added to the enum, the mapping of strings to previous
constants does not change, no matter where the new value is added).

I see no reason to use floats or objects (or resources, or arrays, or
...).

Ben.



html
body
Jarrod Nettles Application Developer - Technology INCCRRA p 309.829.5327

- f 309.828.1808 This e-mail message may contain privileged or confidential
information. If you are not the intended recipient, you may not disclose,
use, disseminate, distribute, copy

  or rely upon this message or attachment in any way. If you received

this e-mail message in error, please return by forwarding the message and
its attachments to the sender. INCCRRA does not accept liability for any
errors, omissions, corruption or virus in

  the contents of this message or any attachments that arises as a result

of e-mail transmission. Please consider your environmental responsibility
before printing this e-mail

/body
/html

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php






--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-18 Thread Ben Schmidt

class Grade {
enum {
A_PLUS,
A,
B_PLUS,
B,
...,
FAIL,
NOT_AVAILABLE,
}
public static function passing($grade) {
return $grade=self::D;
}
}
$grade=Grade::B;
echo Grade::passing($grade)?passing:not passing;



Shouldn't that be:

public static function passing($grade) {
-return $grade=self::D;
+return $grade=self::D;

The passing grades all appear before D in the enum, and I expect those to have
lower values.

Also, I would probably put NOT_AVAILABLE first, since it's underlying value is 
0.
But then the programmer isn't supposed to consider the underlying values...


I agree with all you said.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Clarification on the Enum language structure

2011-02-17 Thread Ben Schmidt

Also, I feel like it should be restricted to integral types only, and
defaults to a zero-based incrementing integer. This is more in line with
other programming languages that already implement enums and will present
expected behavior for people moving over to PHP.


for me that's a plain old interpretation of constants.
constant values were only integer values because of their implementation,
nowadays they could be anything you want, int, float, string and even
objects.


I partially agree with that.

I'm going to be a bit extreme here, but here's a thought:

An enum is something you use conceptually for a set of constant values
which aren't related in a numerical or other fashion (where another type
would make more sense). In an enum, the only meaning of a constant is
the meaning expressed in that constant's name.

So you shouldn't want to use ints, floats, strings, certainly not
objects, for enum values. If you feel yourself wanting to do this, an
enum is not the right datatype for your purpose--you should be using one
of those other types instead, possibly with a very few defined constants
for commonly-used or 'magic' values.

The issue, then, of what type underlies an enum is mostly to do with
internal implementation, and more importantly, serialisation. Integers
are the simplest and most obvious way to do this. But short strings,
particularly string representations of the enum's symbols, could be a
nice way to make serialised data more readable, and less fragile (e.g.
if values are added to the enum, the mapping of strings to previous
constants does not change, no matter where the new value is added).

I see no reason to use floats or objects (or resources, or arrays, or
...).

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Extensions to traits

2011-02-10 Thread Ben Schmidt

On 11/02/11 3:37 AM, Philip Olson wrote:

You now have rights to the wiki rfc namespace.


Thanks a lot, Philip.

I have now made an RFC based on the most recent discussions:

http://wiki.php.net/rfc/traitsmodifications

I think this is a more solid proposal than my original one, and I hope
we can continue to discuss it and agree to the extent that it's worth
starting an implementation.

Please read it and comment whenever you can find some time, guys!

Cheers,

Ben.


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Extensions to traits

2011-02-09 Thread Ben Schmidt

- Don't write long e-mails to a mailing list, write an RFC
http://wiki.php.net/rfc?do=register


OK. I tried to do this. I got an account (username:isfs), but it seems
it is nothing more than an unprivileged account--I don't seem to be able
to edit or add pages at all. What do I need to do to be granted some?

Thanks,

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Change default serialize precision from 100 to 17

2011-02-08 Thread Ben Schmidt

Yes, I think it's dangerous to change the default display precision
lest we have a ton of applications that currently show 0.2 showing
0.20001.


Exactly. And remember, PHP output is not necessarily just for web pages
for humans to read. Other apps may rely on parsing this data, etc., and
may break if precision changes unexpectedly.


Would it be possible to displays a value based on the shortest
decimal fraction that rounds correctly back to the true binary value,
like python 2.7 and 3.1 do ?
(http://docs.python.org/tutorial/floatingpoint.html)


This may be a good idea for trunk, but I don't think it's feasible for
5.3 for the same reason.


Announced as part of a major or point upgrade, I guess this would be OK.

But it still doesn't solve the core problem, which is that the display
precision is being used where it shouldn't be used, e.g. for DB
communications.


Showing shortest decimal fraction that rounds correctly back to the
true binary value works fine for numbers that are directly input, where the 
only
error is the normal rounding error (i.e., total uncertainty for x is x*2^-53).
Once you start making calculations with the numbers the errors start being
propagated, so in these scenarios you would still end up with a lot more ugly
string representations that you have today with the default display precision.


Yeah. For this reason, I think it would be more of a nuisance for the
average app than a help. A lower display precision is actually
desirable.


I agree that the information loss in e.g. PDO must be fixed, but it
seems more appropriate to fix those problems by forcing another
precision only in those cases.


A much better way to fix it.

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] A quick consensus on magic method idea

2011-02-03 Thread Ben Schmidt

On 4/02/11 3:30 PM, Chris Stockton wrote:

Hello,

I haven't seen a magic method proposed in a while so I am not sure how
people feel about them, obviously adding them can break BC (although
it is recommended people should not use __). I'm sure a good amount of
use/desire needs to be shown for inclusion. Here is what I decided I
would like to have and just implemented:

Loader.php:
--
class Loader {
   static public function __compiled() {
 echo I was ran at the end of zend_do_end_class_declaration;
   }
}

Run script:
?php
include Loader.php;

Prints:
I was ran at the end of zend_do_end_class_declaration

At first thought I figured this would be pretty simple to implement,
which it is.. for a basic use case. It seems I will need a bit more
work to handle issues when you do certain things inside __compiled. If
anyone has any interest I would fix it and make a clean patch, so
would anyone find this useful?


Do you yourself have any situation where this is useful? Does it solve
some problem? Does it enable you to do things better than before?

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: Zend mm

2011-01-30 Thread Ben Schmidt

On 30/01/11 4:11 AM, Adi Mutu wrote:
 I have looked at the sources, but i'm only at the begining of
 analyzing the php sources.i've understand how to write extensions
 for example, but this memory manager seems more complicated to me.

Yes, it is. Memory management is a low-level and subtle area. It takes a
lot of careful thought to design and even to understand the algorithms
involved. It is hard to debug, because an error caused in one place may
not show itself until completely different code is executing. It is also
an area which doesn't change much. Almost all the other code in the PHP
interpreter, and therefore PHP scripts themselves, rely on the memory
manager code doing its job unintrusively and correctly, so once it is
working well, it tends to be left that way, except for fixing small bugs
as they are found, or a big and careful development effort to address
some limitation (e.g. improving the garbage collection to collect
cycles, which was something done fairly recently).

The bottom line is that this is not an area that is all that easy for
beginners to get their teeth into. But it's also an area that isn't
necessary for beginners to understand in much detail, either. Unless you
have a particular project in mind that involves the memory manager, you
probably don't need to touch it.

I don't want to discourage you, but just point out that perhaps this is
something you might look at later, or even not at all, as you may find
there are many worthwhile projects that take up all your time before you
ever get to understanding the memory manager fully.

 It would be useful if for example, could explain me the structures
 that are used in the Zend memory manager, how they're chained
 etc.and if you can tell me in words what do zend_mm_aloc_int() and
 zend_mm_free_int() basically do...Thank you for your time,Adrian

I suspect these structures and functions are fairly easy to understand
by someone familiar with the area of memory management, which is why you
have been advised to consult the source code. So perhaps what you need
to do is not learn about PHP's memory manager, but just learn about
memory management in general. Then it should be fairly easy to
understand what PHP's memory manager is doing from its code.

I'm afraid I doubt the people here have the time to teach you this over
email. :-) So here are some references which might be of use to you.

- I believe the 'standard textbook' for learning about memory management
  is this one here:
  http://www.cs.kent.ac.uk/people/staff/rej/gcbook/gcbook.html

- This page also mentions that a new edition is due out soon:
  http://c2.com/cgi/wiki?GarbageCollectionBook

- You can also check out this site: http://www.memorymanagement.org/

- Relating this to, PHP: PHP is a garbage collected language which I
  believe uses reference counting and a clever collector to detect and
  free cycles. I haven't looked in detail into the implementation, but I
  know some documentation is available on the subject here:
  http://www.php.net/manual/en/features.gc.php

Hope this helps!

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] How deep is copy on write?

2011-01-19 Thread Ben Schmidt

On 20/01/11 6:05 AM, la...@garfieldtech.com wrote:

So it sounds like the general answer is that if you pass a complex array to a
function by value and mess with it, data is duplicated for every item you modify
and its direct ancestors up to the root variable but not for the rest of the 
tree.

For objects, because of their pass by handle-type behavior you are (usually)
modifying the same data directly so there's no duplication.

Does that sound correct?


Yes.


Related: What is the overhead of a ZVal? I'm assuming it's a fixed
number of bytes.


It seems not, though a zval has a fixed size. What that size is will
depend on the compiler and architecture of the system being used, or at
least on the ABI.

From zend.h:

typedef union _zvalue_value {
long lval;  /* long value */
double dval;/* double value */
struct {
char *val;
int len;
} str;
HashTable *ht;  /* hash table value */
zend_object_value obj;
} zvalue_value;

struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount__gc;
zend_uchar type;/* active type */
zend_uchar is_ref__gc;
};

The zvalue_value union will probably be 8 or 12 bytes, depending on the
architecture. The whole struct will then probably be between 14 and 24
bytes, depending on the architecture and structure alignment and so on.

For my system:

$ cd php-5.3.3
$ ./configure
$ cd Zend
$ gcc -I. -I../TSRM -x c - END

#include zend.h
int main(void) {
   printf(%lu\n,sizeof(zval));
   return 0;
}
END

$ file ./a.out
./a.out: Mach-O 64-bit executable
$ ./a.out
24
$ gcc -I. -I../TSRM -arch i386 -x c - END

#include zend.h
int main(void) {
   printf(%lu\n,sizeof(zval));
   return 0;
}
END

$ file ./a.out
./a.out: Mach-O executable i386
$ ./a.out
16

You can figure out what you think the overhead is from that. For a
string, arguably the whole structure is overhead, since the string is
stored elsewhere via pointer. Likewise for objects. For a double, the
payload is 8 bytes, and stored in the zval, so there's less overhead. An
integer, with a payload of 4 bytes, is somewhere in between.

Ben.





--Larry Garfield

On 1/19/11 11:27 AM, Gustavo Lopes wrote:

On Wed, 19 Jan 2011 14:23:49 -, Martin Scotta
martinsco...@gmail.com wrote:


What about objects?


With objects less copying occurs because the object value (zval) data is
actually just a pointer and an id that for most purposes works as a
pointer.

However, it should be said that while a copy of an array forces more
memory to be copied, the inner zvals are not actually copied. In this
snippet:

$a = array(1, 2, array(3));
$b = $a;
function separate($dummy) { }
separate($a);

the copy that occurs when you force the separation of the zval that is
shared by $a and $b ($b = $a doesn't copy the array in $a to $b, it
merely copies the zval pointer of $a to $b and increments its reference
count) is just a shallow copy of hash table and a increment of the first
level zvals' refcounts. This means the zvals that have their pointers
stored in the array $a's HashTable are not themselves copied.

Interestingly (or should I say, unfortunately), this happens even if the
inner zvals are references. See
http://php.net/manual/en/language.references.whatdo.php the part on arrays.



class Foo {
public $foo;
}

function test($o) {
$o-foo-foo-foo = 2;
}

$bar = new Foo;
$bar-foo = new Foo;
$bar-foo-foo = new Foo;

test( $bar );


This example shows no copying (in the sense of new zval allocation on
passing or assignment) at all.



---
Also... is it better to pass an object as a parameter rather than many
values?

function withValues($anInteger, $aBool, $aString) {
var_dump($anInteger, $aBool, $aString);
}

function withObject(ParamOject $o) {
var_dump( $o-theInteger(), $o-theBool(), $o-theString() );
}



It should be indifferent. In normal circumstances, there is no zval
copying at all (only the pointers of arguments' symbols are copied).
Only when you start throwing references into the mix will you start
forcing copied.






--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Experiments with a threading library for Zend: spawning a new executor

2011-01-18 Thread Ben Schmidt
Strongly second this. PHP is not a toy language restricted to beginners. If it has 
advanced features, beginners simply don't need to use them.


If anything, I would argue that PHP is a language unsuited to beginners (and other 
scripting languages), as it is so flexible it doesn't enforce good programming 
practice. Java is much more a 'beginner language' because it has much stricter 
syntax, type checking, exception handling, etc., which force and even teach people 
to program well in some regards (or at least do something to raise their awareness 
that they're programming sloppily!). Mind you, it's pretty easy to write bad code 
in any language


Ben.



On 19/01/11 9:36 AM, Hannes Landeholm wrote:

Hello,

I don't think a language becomes a beginners language just because many
new programmers use it. And it's still not a good argument for not including
new features.

As long as the new thread doesn't share any memory/variables with the
spawning context, no reasoning is required at all. It's when you start
sharing objects that things get complex. Just a simple threading
implementation with a strictly defined way to IPC would be very helpful.
It's not super useful in web application programming as handling web
requests is already packaged into small units of work.. web requests. So in
that sense a web application is already multi threaded. However it's
interesting for CGI scripts. The other week I wrote a PHP CGI proxy for
example. Because PHP didn't have threading, I had to bother with select
polling.

Hannes

On 18 January 2011 23:10, Stas Malyshevsmalys...@sugarcrm.com  wrote:


Hi!


  Sorry, but that's my topic, and the most well know interpreters that

'pulled off' threading with shared data are for Java. The interpreter



Given to what complications Java programmers should go to make their
threaded code work, I have a lot of doubt that 95% of PHP users would be
able to write correct threaded programs. Reasoning about threaded programs
is very hard, and IMHO putting it into the beginners language would be a
mistake.

--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php






--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Experiments with a threading library for Zend: spawning a new executor

2011-01-18 Thread Ben Schmidt

On 19/01/11 3:51 PM, Stas Malyshev wrote:

Hi!


If anything, I would argue that PHP is a language unsuited to beginners (and 
other
scripting languages), as it is so flexible it doesn't enforce good programming
practice. Java is much more a 'beginner language' because it has much stricter


Contrary to popular belief, people usually don't start with programming to be
taught good practices and become enlightened in the ways of Art. They usually
start because they need their computers to do something for them. And scripting
languages are often the easiest way to make that happen.
Java, on the other hand, forces you to deal with exceptions, patterns, 
interfaces,
generics, covariants and contravariants, locking, etc. which you neither want 
nor
need to know, only because somebody somewhere decided that it's right for you.


Yeah, well, I was playing Devil's advocate and went a bit far (as you
have too--arguing is fun, isn't it?).

On a more serious note, I think what is much more helpful for beginners
is a good teacher, or good materials to learn from. Almost any language
can be a good one for beginners if taught well. Including PHP; indeed I
have recommended and taught people PHP as beginners without much
trouble. And Java.

At any rate, the important thing is that beginners shouldn't hold a good
language back, particularly if the innovations are not obligatory for
them to use.

Smiles,

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] How deep is copy on write?

2011-01-18 Thread Ben Schmidt
It does the whole of $b. It has to, because when you change 'baz', a reference in 
'bar' needs to change to point to the newly copied 'baz', so 'bar' is 
written...and likewise 'foo' is written.


Ben.



On 19/01/11 5:45 PM, Larry Garfield wrote:

Hi folks.  I have a question about the PHP runtime that I hope is appropriate
for this list.  (If not, please thwap me gently; I bruise easily.)

I know PHP does copy-on-write.  However, how deeply does it copy when
dealing with nested arrays?

This is probably easiest to explain with an example...

$a['foo']['bar']['baz'] = 1;
$a['foo']['bar']['bob'] = 1;
$a['foo']['bar']['narf'] = 1;
$a['foo']['poink']['narf'] = 1;

function test($b) {
   // Assume each of the following lines in isolation...

   // Does this copy just the one variable baz, or the full array?
   $b['foo']['bar']['baz'] = 2;

   // Does this copy $b, or just $b['foo']['poink']?
   $b['foo']['poink']['stuff'] = 3;

   return $b;
}

// I know this is wasteful; I'm trying to figure out just how wasteful.
$a = test($a);

test() in this case should take $b by reference, but I'm trying to determine
how much of a difference it is.  (In practice my use case has a vastly larger
array, so any inefficiencies are multiplied.)

--Larry Garfield



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] How deep is copy on write?

2011-01-18 Thread Ben Schmidt
Yep. PHP does clock up memory very quickly for big arrays, objects with lots of 
members and/or lots of small objects with large overheads. There are a LOT of 
zvals and zobjects and things around the place, and their overhead isn't all that 
small.


Of course, if you go to the trouble to construct arrays using references, you can 
avoid some of that, because a copy-on-write will just copy the reference. It does 
mean you're passing references, though.


$bar['baz'] = 1;
$poink['narf'] = 1;
$a['foo']['bar'] = $bar;
$a['foo']['poink'] = $poink;

Then if you test($a), $bar and $poink will be changed, since they are 'passed by 
reference'--no copying needs to be done. It's almost as if $b were passed by 
reference, but setting $b['blip'] wouldn't show up in $a, because $a itself would 
be copied in that case, including the references, which would continue to refer to 
$bar and $poink. So a much quicker copy, but obviously not the same level of 
isolation that you might expect or desire. Unless you did some jiggerypokery like 
$b_bar=$b['bar']; $b['bar']=$b_bar; which would break the reference and make a 
copy of just that part of the array. But this is a pretty nasty caller-callee 
co-operative kind of thing. Just a thought to throw into the mix, though.


Disclaimer: I'm somewhat out of my depth here. But I'm sure someone will jump on 
me if I'm wrong.


Ben.



On 19/01/11 6:09 PM, Larry Garfield wrote:

That's what I was afraid of.  So it does copy the entire array.  Crap. :-)

Am I correct that each level in the array represents its own ZVal, with the
additional memory overhead a ZVal has (however many bytes that is)?

That is, the array below would have $a, foo, bar, baz, bob, narf, poink,
poink/narf = 8 ZVals?  (That seems logical to me because each its its own
variable that just happens to be an array, but I want to be sure.)

--Larry Garfield

On Wednesday, January 19, 2011 1:01:44 am Ben Schmidt wrote:

It does the whole of $b. It has to, because when you change 'baz', a
reference in 'bar' needs to change to point to the newly copied 'baz', so
'bar' is written...and likewise 'foo' is written.

Ben.

On 19/01/11 5:45 PM, Larry Garfield wrote:

Hi folks.  I have a question about the PHP runtime that I hope is
appropriate for this list.  (If not, please thwap me gently; I bruise
easily.)

I know PHP does copy-on-write.  However, how deeply does it copy when
dealing with nested arrays?

This is probably easiest to explain with an example...

$a['foo']['bar']['baz'] = 1;
$a['foo']['bar']['bob'] = 1;
$a['foo']['bar']['narf'] = 1;
$a['foo']['poink']['narf'] = 1;

function test($b) {

// Assume each of the following lines in isolation...

// Does this copy just the one variable baz, or the full array?
$b['foo']['bar']['baz'] = 2;

// Does this copy $b, or just $b['foo']['poink']?
$b['foo']['poink']['stuff'] = 3;

return $b;

}

// I know this is wasteful; I'm trying to figure out just how wasteful.
$a = test($a);

test() in this case should take $b by reference, but I'm trying to
determine how much of a difference it is.  (In practice my use case has
a vastly larger array, so any inefficiencies are multiplied.)

--Larry Garfield




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] RFC: about class names as values

2011-01-08 Thread Ben Schmidt

I think doing something like this is a good idea for classes and
interfaces.

Ben.



On 7/01/11 1:16 AM, Martin Scotta wrote:

Yes, my intention was to only add a magic constant with the class, similar
to this

namespace Bar {
   class Foo {
 const KLASS = __CLASS__;
   }
}

namespace Buzz {
   use \Bar\Foo as BazFoo;

   class Bar extends BazFoo {
 const KLASS = __CLASS__;
   }

   $bar = new Bar;
   $baz = new BazFoo;

   var_dump( get_class($baz), BazFoo::KLASS);
   var_dump( get_class($bar), Bar::KLASS );
}

This is 100% valid PHP 5.3.3 code, but that includes a lot of effort from
the developer. Someone miss to include the KLASS constant on a class and the
result is undefined.

If that PHP could add a magic constant --named CLASS or whatever you like--
to each class it will reduce the amount of class names hardcoded onto
strings, probably to zero.

The only issue that I found today is related to interfaces. I'm not sure if
they should include this sort of magic constant, but I would rather include
them just for consistency but, as I previously said, I'm not sure about this
one.

  Martin Scotta


2011/1/5 John LeSueurjohn.lesu...@gmail.com




2011/1/5 Johannes Schlüterjohan...@php.net


On Wed, 2011-01-05 at 21:53 -0300, Martin Scotta wrote:

$obj = newInstance( MyClass ); // notice. undefined constant MyClass


This describes the major change with your idea.

What happens if a constant MyClass exists?

Another question is something like this:

?php
function  factory($class) {
return new $class();
}

factory( SomeClass );
?


To proper support this we'd have to make classes first class elements.
For making this consistent it would make sense to make functions first
class elements. And best drop the $ in front of variables and create a
new language. Everything else becomes a mess.

johannes



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



I think he's actually proposing creating for each class the magic class
constant CLASS, so your example becomes:


?php

function factory($class) {
 return new $class();
}

factory( SomeClass::CLASS );

?

This is actually doable without a magic class constant, but requires a
function or class constant to be declared in each class.

?php
class SomeClass {
 const CLASS = __NAMESPACE__ . '\' . __CLASS__;
 static function getNameWithNSPath()
 {
 return __NAMESPACE__ . '\' . __CLASS__;
 }
}


factory( SomeClass::getNameWithNSPath() );
?

Perhaps this could be simplified with traits, if __NAMESPACE__ and
__CLASS__ work in traits that way. In fact, that's an interesting question,
what is __NAMESPACE__ in a trait defined in one namespace, then used in a
class in a different namespace?

I think the point is that the factory function could exist without any
knowledge of the namespaces of the classes it would work on. Then, somewhere
else where the class has been aliased or is otherwise accessible without the
full namespace path, the developer wouldn't need to specify the full
namespace path to the factory, but could ask the class itself what it's full
namespace path was. I don't know that I agree with the idea, but I don't
think it requires making classes first class elements.

John






--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Extensions to traits

2011-01-08 Thread Ben Schmidt

Hi, Jonathan,

On 7/01/11 4:42 AM, Jonathan Bond-Caron wrote:

- New ideas are always welcome


That's great to hear!


- Don't write long e-mails to a mailing list, write an RFC
http://wiki.php.net/rfc?do=register


Sure. Once I've digested and responded to Stefan's replies, I'll work on
putting something up there.

Perhaps this advice would be worth adding to the mailing list rules
page, as nothing about post length is mentioned there at all; it only
talks about attachments.


- Don't overuse the word 'simple'

IMHO, if something is simple it should take 1-2 days to create a
patch. That doesn't seem to be the case with what you're proposing.

But feel free to prove me wrong :)


Yeah, well, I meant simple conceptually, and relatively speaking, not
that it wouldn't take time and effort. I don't think I'll be proving you
wrong! But as I said, I am willing to get my hands dirty with this.


Creating a patch will help getting feedback about what you're proposing
http://ca3.php.net/reST/php-src/README.MAILINGLIST_RULES


I hope I haven't broken any of the mailing list rules, but my apologies
if I have, and please point out specifically where I've gone wrong.

As far as a patch goes, I don't think that is appropriate at this stage.
I don't want to spend a lot of time creating a patch only to have it
rejected if this could be avoided by a little discussion. My time is too
valuable to me to waste like that, and with something as controversial
as this, there's a real danger of that happening.

Cheers,

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Extensions to traits

2011-01-08 Thread Ben Schmidt

Hi, Stefan,

Thanks for considering my ideas so carefully and for your detailed
replies.


The reason to go with insteadof is that the assignment syntax hides
changes that might cause problems.

Thus, when you change any of the traits participating in a composition
in a way that a conflict would be introduced, the assignment syntax is
hiding this. With the insteadof syntax you are actually forced to
reevaluate whether your code still makes sense and include the
offending change explicitly.


OK. That makes sense. I'll rework any surviving parts of my proposal to
be based on the insteadof syntax.


This does not only have the mentioned benefit of making problematic
changes in the traits hierarchy explicit, but the second reason to go
with this design was the wish to have a 'exclude' operator without
actually having a full-exclude operator. Thus, there is no way that
you can leave out arbitrary methods from a trait.


This seems wrong to me. Doesn't it go against the stated principle that
the class author should have full control of traits? How is it full
control if you can't exclude a method? What is the reasoning behind this
wish not to have a full exclude operator?


Hm, don't understand you here either. I needed to look up what
impoverished actually means, you are not insulting me here, right?
Just kidding ;)


Sorry. I forget that a lot of you people aren't native English speakers
and sometimes funny words like that slip in! I think all you people who
communicate so fluently in additional languages are amazing.


No error or warning will be
generated, but the class will not work as intended; probably it will
infinitely recurse; a nasty problem to track down.
Furthermore, even if the incorrect method call didn't occur, there would
be data-sharing problems, as both the ErrorReporting trait and the
class' print() function make use of the $output data member,
unintentially sharing data.


Well, short answer: it is compiler-assisted copy-and-past, why isn't
that trait just providing the glue that gets your class the necessary
functionality to use a proper ErrorReporting class?

Sorry, I know not a really helpful answer, but I hope that examples
shows how I see traits.

They are for reusing code in situations where the other concepts just
break down. Not meant to replace those.


I agree. I did say it was a poor example. I think the kinds of
behavioural problems it demonstrates, though, could be found in
situations where traits *are* truly appropriate.

No need to argue over examples, though. Plenty of other things to argue
about. :-)


Warnings
- - - -

To avoid silent unintended shadowing, I suggest issuing a warning when a
conflict between trait and class methods occurs. So this would trigger
a warning:

   trait SaySomething {
  public function sayIt() {
 echo Something\n;
  }
   }
   class Sayer {
  use SaySomething;
  public function sayIt() {
 echo Hello world!\n;
  }
   }


Ok, well, we could see the actual class body as another trait, and
require it to follow the same composition rules, and that way make
require the programmer to use insteadof in such a case.

In return that would mean, that traits are not part of the inheritance
chain at all anymore.

Thus, first is the inheritance chain used to build up the
implementation of a class, and afterwards all the traits are composed,
while the original class is seen as another trait.

That idea has certainly something to it.


Yes, I think that would be good.

Having read your other emails, as well as having allowed my proposal
itself to clarify in my mind, I'm beginning to think it might be
clearest and cleverest to avoid inheritance altogether with traits. Of
course, this is in contrast to my original proposal, which was to
increase traits' participation in inheritance.

In this case, parent:: will always do what you expect then, and there's
no need for prev::.

Now to the other emails!

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Extensions to traits

2011-01-08 Thread Ben Schmidt

Hi again, Stefan,

Continuing the conversation.

On 7/01/11 10:18 AM, Stefan Marr wrote:

On 02 Jan 2011, at 13:16, Ben Schmidt wrote:

Extension
- - - - -

I suggest these two problems can be simply solved by introducing two
additional uses of the trait keyword: as a scoping keyword and an access
specifier.

As a scoping keyword, it would be used analogously to self. Method calls
such as $this-print() could be replaced with trait::print() when the
programmer desires to ensure that their trait method, and only their
trait method, is called--when there is no intention that overriding
should be possible. It would only be able to be used in a trait, and
could only be used to reference methods or properties defined in the
same trait, using their original name.

As an access specifier, it would be used instead of public, private,
etc. in trait definitions, to mean that the member (data or method) can
and can only be accessed using the mechanism above (trait::).


Ok, that would actually get us around all the meta-programming
problems.

When you say that the 'trait'-access modifier always requires the
access via a specific keyword (trait::) then mangling the name should
be possible.

On the other hand, what would iterating over the object properties
show?

Multiple properties with the same name, like with inherited private
properties I suppose?


Well, I hadn't thought about it before. :-)

But yes, I think that makes perfect sense.


And an occurrence of trait:: would mean, do a $this-  but mangle the
name first with the trait's name the original definition was in.
Should be possible, but would certainly impact the Zend Engine a bit
more than what we have now.


One complication I hadn't thought of before is whether it should be
possible to access trait:: methods and properties in different objects.
And if it should be, what syntax to use. $that-trait::method() seems
somewhat ugly to me. That would also suggest we should use
$this-trait::method() for the same-object case.


Certainly an interesting approach.

Has someone else an opinion on that?


I think actually this is the most important part of my proposal, so if
it could be accepted, I would be very pleased. Obviously it does need a
bit more thought and discussion yet, though.


Overriding
==

Limitation
--

At present, the overriding semantics of traits are that a method defined
in a class proper overrides a method defined in a used trait which in
turn overrides a method defined in an ancestor class.


Bye the way, where comes that terminology from: class proper? We are
talking about the body of a class, right?


Yes. 'Class proper' = 'class itself'. We seem to use 'proper' in English
as an adjective after a noun with a Latin-like sense of 'own/itself'. I
guess we probably got it from French, and surprisingly it hasn't died
out.

Cheers,

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Extensions to traits

2011-01-08 Thread Ben Schmidt

Hi, Stefan,

I think if the other stuff goes ahead, we can probably scrap what I
originally proposed here. But perhaps something else would be helpful. I
won't comment very specifically on aspects of my original proposal, but
will just raise some new ideas for consideration and further thought.

It all hinges on aliasing: how it works and how it can be avoided when
necessary. Your comment on my example made this most clear.


   abstract class ActiveRecord {
  protected $new;
  protected $id;
  protected $other_values;
  protected function __construct($id,$values,$new) {
 $this-id=$id;
 $this-other_values=$values;
 $this-new=$new;
  }
  public function save() {
 if ($this-new) {
if (!create_in_the_database()) return false;
if ($this-id===null) $this-id=last_insert_id();
 } else {
if (!update_in_the_database()) return false;
 }
 return true;
  }
  public static function new() {
 return new static(null,static::$default_values,true);
  }
  public static function get($id) {
 return new static($id,get_from_the_database(),false);
  }
   }
   trait LoggingOperations {
  public function save() {
 if ($this-new) {
log(Creating .get_called_class());
 } else {
log(Updating .get_called_class(). ID .$this-id);
 }
 if (!prev::save()) {
log(Failed);
return false;
 }
 log(Succeeded);
 return true;
  }
   }
   trait EnsuringNoConcurrentChanges {
  trait $original_values = array();
  protected function setOriginalValues($values) {
 trait::$original_values = $values;
  }
  public static function get($id) {
 $record = prev::get($id);
 $record-setOriginalValues($record-other_values);
 return $record;
  }
  public function save() {
 $current_values=select_from_database();
 if ($this-new$current_values) return false;
 if (!$this-new!$current_values) return false;
 if ($current_values!=trait::$original_values) return false;
 return prev::save();
  }
   }
   trait UsingHashesForIDs {
  public function save() {
 if ($this-id===null) $this-id=random_hash();
 return prev::save();
  }
   }
   class SessionRecord extends ActiveRecord {
  protected static $default_values=array(
 'user'='',
 'time'=''
  );
  use UsingHashesForIDs;
   }
   class Client extends ActiveRecord {
  protected static $default_values=array(
 'user'='',
 'name'='',
 'address'=''
  );
  use EnsuringNoConcurrentChanges, LoggingOperations {
 save = EnsuringNoConcurrentChanges::save,
   LoggingOperations::save;
  }
   }


Ok, that example is, well, not actually helping you.

You can do all the things here without your extensions, I believe.


Before commenting speciically I'd like to point out that whether
something *can* be done shouldn't be the only thing considered. Other
important aspects are how easily it can be done, how tidily it can be
done, how much code duplication it requires, and so on. Sometimes, a
construct by merely providing elegance, without any additional power, is
worthwhile. In fact, you *can* model any program as a Turing machine, so
we actually need very little; but there aren't many popular languages
like that!

In this case, though, I think there are a couple of shortcomings in the
current trait behaviour that mean this can't quite be done reliably.

One thing of note is the use of the trait-scoped property, making the
trait more robust. That was the subject of an earlier email, and one of
the parts of the proposal you viewed most favourably, so I'm happy about
that. I won't dwell on it here.


Your problem with the save methods is solved by aliases and parent::
(parent:: only has semantics with respect to inheritance, so it will
do the right thing.

Your Client will have a save method that calls the aliased versions of
the saves in the order you want.

And in get() you can also just use parent::, no?


Aliases come a long way, and to be honest, I am still coming to terms
with how powerful they are, particularly in combination with traits'
ability to have abstract methods.

But there is at least one missing link.

You can't reliably use parent:: in a trait method, because that
jeopardises the reusability of the trait. In some composing classes, you
might want it to call a method that isn't from the superclass. In this
minimal example, parent:: happens to work; but that shouldn't be relied
upon when writing a trait, and in the generalised case, where there are
more traits and more composition combinations, it would fall apart.

This means at the very least, you would have to use a method declared in
the trait, and then write forwarding methods. In this case, you have
basically 

Re: [PHP-DEV] Extensions to traits

2011-01-08 Thread Ben Schmidt

In fact, this is so nice, could I suggest it would be nice to allow
other delegation-like forwarding to be done like this? You could have
'use' without a trait even, just like this:

use {
   $queue-add as addToQueue;
}

Since the properties' object wouldn't be available at compile time, this
extra ability would probably have to be implemented by basically
generating an addToQueue method, and it wouldn't work with arguments
passed by reference. It would basically be a shorthand for

public function addToQueue() {
   return call_user_func(array($queue,'add'),func_get_args());
}

but much more elegant.


Of course should have been

public function addToQueue() {
   return call_user_func(array($this-queue,'add'),func_get_args());
}

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Traits and Properties

2011-01-03 Thread Ben Schmidt

Hi, Stefan,


Sorry, I do not understand.


Haha. Now we are both confused!

In this email thread you seemed to be saying that properties defined in
traits are completely ignored, but in the RFC and svn it seems to be
saying that properties in traits are not ignored, but are merged into
the class and/or trigger errors/warnings. So, which is it? Ignored or
not? Or is some aspect of them ignored and some aspect not?

I hope I'm not making things more confusing

Cheers,

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Traits and Properties

2011-01-03 Thread Ben Schmidt

Hi, Stefan,

On 3/01/11 8:16 PM, Stefan Marr wrote:

On 03 Jan 2011, at 10:04, Ben Schmidt wrote:

In this email thread you seemed to be saying that properties defined in
traits are completely ignored, but in the RFC and svn it seems to be
saying that properties in traits are not ignored, but are merged into
the class and/or trigger errors/warnings. So, which is it? Ignored or
not? Or is some aspect of them ignored and some aspect not?


The RFC was discussed on this list, and the RFC should explain what
the current state of the implementation is. So, the RFC and the
implementation are the specifications. In case they differ it has to
be fixed.


OK. So this comment from your email is outdated?:


However, at the moment it is possible to define properties in a trait:

trait Foo {
  private $a;
  public  $foo;
}

For the moment, that information is completely ignored, thus:

class Bar {
  use Foo;
}
property_exists('Bar', 'a') === false


in light of this test:

http://svn.php.net/viewvc/php/php-src/trunk/Zend/tests/traits/property002.phpt?view=markuppathrev=306476

Maybe the only thing that was confusing is that somebody replied to an
old email?

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Traits and Properties

2011-01-03 Thread Ben Schmidt

On 3/01/11 8:57 PM, Stefan Marr wrote:

Hi Ben:

On 03 Jan 2011, at 10:35, Ben Schmidt wrote:


OK. So this comment from your email is outdated?:


Yes, outdated since this email:
http://marc.info/?l=php-internalsm=129288735205036w=2

Best regards
Stefan


OK, Stefan, I just got confused by reading your outdated message that was quoted 
in a recent reply, and by the fact that the last update date of 2010-11-18 at 
the top of the RFC is inaccurate, so I assumed the email was more current than it 
was. Seems like the RFC was actually updated circa 2010-12-20. :-)


Sorry for the noise, guys.

Ben.



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



[PHP-DEV] Extensions to traits

2011-01-02 Thread Ben Schmidt

Hello, PHP developers,

I'm new to the list, but have been using PHP for a number of years, have
done a little hacking in the source code, and have an interest in the
development of the language.

Particularly recently I have been reading with a good deal of excitement
Stefan Marr's RFC on 'horizontal reuse' on the PHP Wiki:
http://wiki.php.net/rfc/horizontalreuse

The trait functionality looks like a great start and an innovative
language development, and I'm looking forward to trying it out soon
(when I can find some more time!), and particularly looking forward to
making good use of it when it makes it into a release.

While it's still in the pre-release stage, though, I would like to put
in a vote for the assignment syntax: I think it is a lot easier to read
and understand than the 'insteadof' syntax.

I would also like to propose some extensions to the functionality as
currently described, which I think could potentially add tremendous
power to the mechanism, with relatively little additional conceptual
complexity and implementation effort. I've written it up as a bit of a
proposal below.

I'd love to hear what you think.

I would be willing to play a part implementing it, too.

Cheers,

Ben.



=
Proposed extensions to traits
=

Background
==

Traits in PHP [1] enable improved code reuse. They can be simplistically
viewed as compiler-assisted copy-and-paste. Methods designed to be
reused can be defined in traits and then these traits can be used in
classes. The traits are 'flattened', so it is as if the trait methods
were defined directly in the class in which they are used. Traits can
access other methods and properties of the class, including those of
other traits. They also fit in with the method overriding system:
methods defined directly in a class override those in used traits, which
in turn override those in ancestor classes.

There are two limitations of traits in their current implementation for
which I would like to propose extensions. The first limitation is that
traits can very easily break, particularly when methods are omitted from
classes in which the rest of the trait is used, or shadowed by method
definitions in the class proper. The second limitation is that the trait
overriding semantics are impoverished and needlessly restrictive.

Breakability


Limitation
--

There are two main aspects of traits which make them easy to break:
incorrect method calls and unintentionally shared state.

Incorrect method calls spring from the way trait methods can be omitted
from classes where the rest of the trait is used, or shadowed by methods
defined in the class proper. In either of these scenarios, any call in a
trait to such a method may not call the method that was originally
intended--they may fail, or they may call a different method, with
unpredictable results. Of course, sometimes such a behaviour is
desirable, if writing a trait which communicates with the rest of the
class by means of method calls, yet provides a fallback methods in case
the class author does not wish to provide such methods. However, when it
is not intended, this could lead to incorrect and difficult-to-pinpoint
behaviour.

The other way traits can break is by unintentionally sharing state.
Traits may make use of the same data members (not recommended, but
possible), or the same accessors, when each should actually have their
own independent state. Again, this could lead to incorrect and
difficult-to-pinpoint behaviour.

Example
---

trait ErrorReporting {
   public function error($message) {
  $this-print($message);
   }
   private function print($message) {
  fputs($this-output,$message.\n);
   }
}

class Printer {
   use ErrorReporting;
   public $output=null;
   public function print($document) {
  /* Send the document to the printer--$this-output. */
  /* ... */
  if (there_was_an_error()) {
 $this-error(printing failed);
  }
  /* ... */
   }
}

This example is very contrived, and hopefully no programmer would be
silly enough to fall into this exact trap. However, it is easy to
imagine more subtle cases where this kind of thing could happen,
particularly as traits and classes are modified from their original
conception.

The ErrorReporting trait allows the programmer to report errors in a
consistent way by using the trait in many classes. It includes a print()
method that is used to print the error to the screen. However, this
method has been unintentionally shadowed by a print method in the class,
intended to print a document on a printer. No error or warning will be
generated, but the class will not work as intended; probably it will
infinitely recurse; a nasty problem to track down.

Furthermore, even if the incorrect method call didn't occur, there would
be data-sharing problems, as both the ErrorReporting trait and the
class' print() function make use of the $output data member,

Re: [PHP-DEV] Traits and Properties

2011-01-02 Thread Ben Schmidt

On 3/01/11 2:24 PM, David Muir wrote:

On 12/12/10 01:47, Stefan Marr wrote:

Hi:

Traits do not provide any special provisioning for handling properties,
especially, there is no language solution for handling colliding property names.
The current solution/idiom for handling state safely in a trait is to use either
abstract set/get methods or an abstract get that returns a reference to the
property in the class.

However, at the moment it is possible to define properties in a trait:

trait Foo {
private $a;
public $foo;
}

For the moment, that information is completely ignored, thus:

class Bar {
use Foo;
}
property_exists('Bar', 'a') === false


Well, and that is a rather inconsistent status-quo.

I would like to have that fixed in one or another way.

One possibility would be to forbid property definition in a trait altogether.
That reduces a bit the possibility to have wrong expectations about properties,
however, the dynamic property creation is still possible.

Another way would be to merge the properties in the composing class.
The question here would be how to treat visibility modifiers: how to merge
public and private, should it result in public, or private?
And, to discorage users to go this way, should there be a STRICT notice? Options
here are a notice whenever a property is defined in a trait, or whenever
properties are silently merged.


Comments very welcome.

Thanks
Stefan



What about extending the way that traits resolve method conflicts to solve
property conflicts in a similar fashion? I can't remember if it's already been
suggested and and maybe shot down already. It would probably get horrendously
messy, but figured I'd mention it anyway.

Cheers,
David


I'm a latecomer here, but...

Stefan, doesn't this conflict with what you've written here (and the
test cases in SVN)?:

http://wiki.php.net/rfc/horizontalreuse#handling_of_propertiesstate

Or is what is happening here that the properties in traits are treated
essentially as declarations rather than definitions, triggering errors
but not actually creating properties, and you think they should actually
create properties?

Ben.




--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php