RE: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Andi Gutmans
Hi Christian,

This is a very nice piece of work. Definitely addresses a lot of the issues we 
have raised in the past.
I would like to see such a solution make its way into PHP (see below re: 
timing).   

There are some things I'd like to consider:
1) I am not sure that the current semantics of the lexical keyword is great 
in all cases. Is the reason why you don't allow by-value binding so that we 
don't have to manage more than one lambda instance per declaration?
2) [minor curiosity - do we want to consider reusing parent instead of 
lexical? I guess that could be confusing but it's not the first time we reuse 
a keyword when it's clear that the usage is in two different places (this is 
minor and I don't mind much either way although lexical doesn't mean too much 
to me).]
3) I am concerned about binding to classes. First of all we need to look into 
more detail what the implications are for bytecode caches when changing class 
entries at run-time. We may want to also consider an option where the lambda 
binds to the object and only has public access although I realize that may be 
considered by some as too limiting. We'll review these two things in the coming 
days.

Re: timing, I think the biggest issue we have right now with PHP 5.3 is that we 
are not making a clear cut on features. There's always pressure on release 
managers to include more (I went through the same with 5.0) but at some point 
you just have to stop at some place or things will never go out as there are 
always good ideas flowing in. Unfortunately with 5.3 that cut isn't happening 
and it seems to drag out longer than needed. I prefer having this discussion in 
the context of a hard date for a beta release after which we'll be especially 
strict with accepting new features. Each new feature will drag out the beta/RC 
cycle as they need enough time for testing/feedback/tweaks.

Andi

 -Original Message-
 From: Christian Seiler [mailto:[EMAIL PROTECTED]
 Sent: Monday, June 16, 2008 10:39 AM
 To: php-dev List
 Subject: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
 
 Hi,
 
 As a followup to the discussion in January, I'd like post a revised patch to
 this list that implements closures and anonymous functions in PHP.
 
 INTRODUCTION
 
 
 Closures and lambda functions can make programming much easier in
 several ways:
 
   1. Lambda functions allow the quick definition of throw-away functions
  that are not used elsewhere. Imaging for example a piece of code that
  needs to call preg_replace_callback(). Currently, there are three
  possibilities to acchieve this:
 
   a. Define the callback function elsewhere. This distributes code that
  belongs together throughout the file and decreases readability.
 
   b. Define the callback function in-place (but with a name). In
 that case
  one has to use function_exists() to make sure the function is only
  defined once. Example code:
 
   ?php
  function replace_spaces ($text) {
if (!function_exists ('replace_spaces_helper')) {
  function replace_spaces_helper ($matches) {
return str_replace ($matches[1], ' ', 'nbsp;').' ';
  }
}
return preg_replace_callback ('/( +) /',
 'replace_spaces_helper',
  $text);
  }
   ?
 
  Here, the additional if() around the function definition makes the
  source code difficult to read.
 
   c. Use the present create_function() in order to create a function at
  runtime. This approach has several disadvantages: First of all,
 syntax
  highlighting does not work because a string is passed to the
 function.
  It also compiles the function at run time and not at compile
 time so
  opcode caches can't cache the function.
 
   2. Closures provide a very useful tool in order to make lambda
 functions even
  more useful. Just imagine you want to replace 'hello' through
 'goodbye' in
  all elements of an array. PHP provides the array_map() function which
  accepts a callback. If you don't wan't to hard-code 'hello' and
 'goodbye'
  into your sourcecode, you have only four choices:
 
   a. Use create_function(). But then you may only pass literal values
  (strings, integers, floats) into the function, objects at best as
  clones (if var_export() allows for it) and resources not at
 all. And
  you have to worry about escaping everything correctly.
 Especially when
  handling user input this can lead to all sorts of security issues.
 
   b. Write a function that uses global variables. This is ugly,
  non-reentrant and bad style.
 
   c. Create an entire class, instantiate it and pass the member function
  as a callback. This is perhaps the cleanest solution for this
 problem
  

[PHP-DEV] Selectable error messages

2008-06-18 Thread Lester Caine
OK - I've got PHP5.3.0-dev up at the moment in order to test the Firebird 
stuff, so display_errors is on. I need it on anyway while testing code.


The 'problem' I am having is that of cause none of the other PHP stuff I'm 
using is currently not compatible with PHP5.3 so generates a lot of deprecated 
warnings in particular.


Current one is phpDocumentor which uses is_a() extensively, and has a function 
to replicate it for backwards compatibility.


Short of switching display_errors on and off all the time, how do other people 
handle this irritation? I could repair phpDocumentor in this case and ignore 
BC as I will not be running THAT on older version of PHP, and since a run is 
taking 30 minutes it would be interesting to see if there is any improvement 
to time.


 bit the bullet - my copy of phpDocumentor has no is_a() in it 

--
Lester Caine - G8HFL
-
Contact - http://lsces.co.uk/lsces/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk//
Firebird - http://www.firebirdsql.org/index.php

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



Re: [PHP-DEV] Selectable error messages

2008-06-18 Thread Pierre Joye
hi Lester,

On Wed, Jun 18, 2008 at 9:14 AM, Lester Caine [EMAIL PROTECTED] wrote:

 Short of switching display_errors on and off all the time, how do other
 people handle this irritation? I could repair phpDocumentor in this case and
 ignore BC as I will not be running THAT on older version of PHP, and since a
 run is taking 30 minutes it would be interesting to see if there is any
 improvement to time.

Use error_reporting in your php.ini or within your applicaion:
error_reporting(E_ALL ^ E_DEPRECATED);

Cheers,
--
Pierre

http://blog.thepimp.net | http://www.libgd.org

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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Gwynne Raskind

On Jun 18, 2008, at 2:36 AM, Alexey Zakhlestin wrote:
1) I am not sure that the current semantics of the lexical  
keyword is great in all cases. Is the reason why you don't allow by- 
value binding so that we don't have to manage more than one lambda  
instance per declaration?

by-reference binding is much closer to other languages symantics. I
guess, that was the main reason Christian chose it.
by-value may still exist, if people find, that they need it, but
only in addition, please.

lambda has to reflect changing state of context, to be truly useful


In Lua, the language in which I've seen the most of closures and  
lambda, lexical scoping is handled this way:


someVariable1 = asdf;
someVariable2 = jkl;;
SomeFunction = function()
local someVariable2 = 1234;

print someVariable1.. ..someVariable2..\n;
end
print gettype(SomeFunction)..\n;
SomeFunction();
someVariable1 = qwer;
someVariable2 0987;
SomeFunction();

The resulting output of this code fragment would be:
function
asdf 1234
qwer 1234

The Lua interpreter handles this by resolving variable references as  
they're made; someVariable1 is looked up in the closure's scope and  
not found, so the interpreter steps out one scope and looks for it  
there, repeat as necessary. Once found outside the closure's scope,  
something similar to the proposed lexical keyword happens. Closures  
and lexical variables can be nested this way, to the point where a  
single variable in a sixth-level closure could still have been  
originally found in the global scope.


I'm not sure this would work for PHP, I'm curious what others think.

Of course, that fragment does a very poor job of showing off the  
extreme flexibility of Lua with regards to functions and scoping, but  
hopefully it illustrates the concept.


-- Gwynne, Daughter of the Code
This whole world is an asylum for the incurable.


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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Richard Quadling
2008/6/18 Gwynne Raskind [EMAIL PROTECTED]:

 On Jun 18, 2008, at 2:36 AM, Alexey Zakhlestin wrote:

 1) I am not sure that the current semantics of the lexical keyword is
 great in all cases. Is the reason why you don't allow by-value binding so
 that we don't have to manage more than one lambda instance per declaration?

 by-reference binding is much closer to other languages symantics. I
 guess, that was the main reason Christian chose it.
 by-value may still exist, if people find, that they need it, but
 only in addition, please.

 lambda has to reflect changing state of context, to be truly useful


 In Lua, the language in which I've seen the most of closures and lambda,
 lexical scoping is handled this way:

 someVariable1 = asdf;
 someVariable2 = jkl;;
 SomeFunction = function()
local someVariable2 = 1234;

print someVariable1.. ..someVariable2..\n;
 end
 print gettype(SomeFunction)..\n;
 SomeFunction();
 someVariable1 = qwer;
 someVariable2 0987;
 SomeFunction();

 The resulting output of this code fragment would be:
 function
 asdf 1234
 qwer 1234

 The Lua interpreter handles this by resolving variable references as
 they're made; someVariable1 is looked up in the closure's scope and not
 found, so the interpreter steps out one scope and looks for it there, repeat
 as necessary. Once found outside the closure's scope, something similar to
 the proposed lexical keyword happens. Closures and lexical variables can
 be nested this way, to the point where a single variable in a sixth-level
 closure could still have been originally found in the global scope.

 I'm not sure this would work for PHP, I'm curious what others think.

 Of course, that fragment does a very poor job of showing off the extreme
 flexibility of Lua with regards to functions and scoping, but hopefully it
 illustrates the concept.

 -- Gwynne, Daughter of the Code
 This whole world is an asylum for the incurable.



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


Is nested scope just the same as namespace in this regard?



-- 
-
Richard Quadling
Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498r=213474731
Standing on the shoulders of some very clever giants!


Re: [PHP-DEV] FastArray, great addition

2008-06-18 Thread Antony Dovgal

On 16.06.2008 14:28, Pierre Joye wrote:

My only wish is to actually respect the informal decision we took a
while back, to do not use fast, improved, better or similar
wording in function or extension names. What's about naming it CArray
or something similar? To reflect what it is, it is not a fast(er) hash
table like our current array, it is a C-like array.


I can live with any name, so feel free to choose whatever you like most.

offtopic
Though I'd like to be able to cast these arrays to PHP's arrays 
and we need to implement get_properties() handler for that.
If there are no objections, I'll commit my patch when 
I get back home (30th of June).


--
Wbr, 
Antony Dovgal


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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Christian Seiler

Hi!


- I am a little confused about the OOP interaction.  How does a function
become a public method of the class?

To clarify: the public method ist just the internal representation of
the lambda function and has *nothing* to do with the semantics of
calling the lambda itself. The method only means that the lambda
function defined inside another method can access the class members and
public only means that the lambda function can still be called from
outside the class.


If one knew how to access it, which it seems is not possible/feasible for 
user-space code.  


No, that's not what I meant. The engine uses the following internal trick:

 a) Upon copmilation, my patch simply adds the lambdas as normal
functions to the function table with an automatically generated
unique (!) name. If it happens to be defined within a class method,
the function will be added as a public final method to that class.

 b) That added function is not directly callable due to checks of a flag
in the internal structure of that function.

 c) At the place of the function definition the compiler leaves an
opcode grab function $generatedname and make a closure out of it.
This opcode then looks up the generated lambda function, copies the
function structure, saves the bound variables in that structure and
returns the copied structure as a resource.

 d) Normally, when a function is called, the name is looked up in the
function table. The function structure that is retrieved from there
is then used to execute the function. Since a lambda resource is
already a function structure, there is no necessity to look up
anything in the function table but the function structure can be
directly passed on to the executor.

Please note step d): The closure functionality only changes the *lookup*
of the function - so instead of getting the function structure from a
hash table lookup I get the function structure by retrieving it from the
resource. But *after* the lookup of a class method there are checks for
the access protection of that method. So these access protection checks
also apply to closures that were called. If a lambda function was not
declared public, it could not be used outside of the class it was
defined in. Perhaps this makes it clearer?

I see.  It would be great if you could update the RFC with this information so 
that it's clearer.  


Done: http://wiki.php.net/rfc/closures


Two other questions that just occurred to me:

1) What is the interaction with namespaces, if any?  Are lambdas as 
implemented here ignorant of namespace, or do they take the namespace where 
they are lexically defined?


My patch itself is namespace-ignorant, but the net result is not:

 a) The generated internal function names do not contain the current
namespace name, but since namespace names in function names are only
used for lookup if you want to call the function. And calling
lambdas by name (!) directly doesn't work anyway (is not supposed
to work) so this poses no problem.

 b) The code *inside* the closure is namespace-aware because the
information of which namespace is used is added at compile time.
Either the name lookup is done entirely at compile time or the
current compiler namespace is automatically added to all runtime
lookup calls (this is already the case with current code). So
the information which namespace a function resides in is currently
*irrelevant* at runtime when calling other functions.

For (b) let me make two examples:

Suppose you have the following code:

namespace Foo;

function baz () {
  return Hello World!\n;
}

function bar () {
  return function () {
echo baz ();
  };
}

and in another file:

$lambda = Foo::bar ();
$lambda ();

This will - as expected - print Hello World!\n.

The reason is that the compiler upon arriving at the baz() function call
inside the closure already looks up the function in the function table
directly (it knows the current namespace) - and simply creates a series
of opcodes that will call the function with the name Foo::baz (the
lookup is already done at compile time).

Consider this other code:

foo-bar.php:

namespace Foo;

function bar () {
  return function () {
echo baz ();
  };
}

foo-baz.php:

namespace Foo;

function baz () {
  return Hello World!\n;
}

baz.php:

function baz () {
  return PHP!\n;
}

test1.php:

require 'foo-bar.php';
require 'foo-baz.php';

$lambda = Foo::bar ();
$lambda ();

test2.php:

require 'foo-bar.php';
require 'baz.php';

$lambda = Foo::bar ();
$lambda ();

Running test1.php yields Hello World! whereas running test2.php yields
PHP!. Why is this? Because when the compiler reaches the baz ()
function call in the closure, it cannot find the function so it cannot
determine whether it's a function in global or in namespace scope. So it
will simply add a series of opcodes that say try Foo::bar and if that
does not exist try bar. Here again, Foo:: is added by 

Re: [PHP-DEV] Selectable error messages

2008-06-18 Thread Christian Schmidt

Lester Caine wrote:

Short of switching display_errors on and off all the time, how do other
people handle this irritation?


I don't have experiences with E_DEPRECATED, but for E_STRICT we use a 
custom error handler to surpress strict errors in external libraries. 
Not all E_STRICT errors can be caught in this way, especially not if you 
are using an opcode cache.


Our error handler looks like this, perhaps you can do something similar 
for E_DEPRECATED.:



if (!($errorNumber  error_reporting()) ||
$errorNumber == E_STRICT 
(strpos($fileName, '/pear/') !== false ||
 strpos($fileName, '/smarty/') !== false ||
 preg_match('/^Non-static method (DB|HTTP|Mail_RFC822|PEAR)::/',
$message))) {

if ($errorNumber  (E_ERROR | E_RECOVERABLE_ERROR | E_USER_ERROR)) {
exit;
}
return;
}
// Show error message etc.


Christian

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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Christian Seiler

Hi!


1) I am not sure that the current semantics of the lexical keyword
is great in all cases. Is the reason why you don't allow by-value
binding so that we don't have to manage more than one lambda instance
per declaration?


First of all: global and static are also used to create references to
other variables (OK, with static they are not visible to the outside,
but nevertheless...) and second because other languages do the same. As
someone corrected me a while ago, even JS uses references, test the
following JavaScript code:

function foo () {
var x = 5;
var f = function (n) {
  x += n;
};
alert (x);
f (2);
alert (x);
}

foo ();

That will yield first 5 and then 7.


2) [minor curiosity - do we want to consider reusing parent instead
of lexical? I guess that could be confusing but it's not the first
time we reuse a keyword when it's clear that the usage is in two
different places (this is minor and I don't mind much either way
although lexical doesn't mean too much to me).]


Consider this code:

class A {
  public function printSomething ($var) {
echo $var\n;
  }
}

class B extends A {
  public function printSomething ($var) {
$printer = function () {
  parent $var;
  parent::printSomething ('I print: ' . $var);
};
$printer ();
  }
}

Yeah, of course, my example is extremely stupid since it could be done
entirely without closures but I really dread the perspective of having
to explain someone the difference between those two lines...


3) I am concerned about binding to classes. First of all we need to
look into more detail what the implications are for bytecode caches
when changing class entries at run-time.


Well, that's the thing: My patch does NOT change classes at runtime, so
that is totally a non-issue. :-)

When creating a lambda function inside a class method, it adds a new
class method for the lambda function at compile time (!). This
compile-time added method has a dynamic name (__compiled_lambda_F_N
where F is the filename and N is a per-file counteŕ). To an opcode cache
processing this class this added method will appear no different than a
normal class method - it can be cached just the same.

Now, upon execution of the code containing the closure, the new opcode
just copies the zend_function structure into a copy, registers that copy
as a resource and returns that resource. As soon as the resource is
garbage collected (or explicitly unset), the op_array copy is destroyed.
No modification of the actual class is done at all - the cache remains
happy.

Just for clarity I have posted a sample output of PHP with my Patch and
VLD active (153 is the new ZEND_DECLARE_LAMBDA_FUNC opcode that VLD
does not yet know about):

http://www.christian-seiler.de/temp/php-closure-opcodes.txt

Perhaps this helps to understand better how my patch works?


We may want to also consider an option where the lambda binds to the
object and only has public access although I realize that may be
considered by some as too limiting. We'll review these two things in
the coming days.


What do you mean with binds to the object?

But if you only want to grant access to public object members: If I
declare a closure inside a class method, from a programmers point of
view I am still within that class - why shouldn't I be able to access
all class properties there? I would find such a limitation quite odd
(and technically unecessary).

Regards,
Christian

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



Re: [PHP-DEV] FastArray, great addition

2008-06-18 Thread Alexey Zakhlestin
On 6/18/08, Antony Dovgal [EMAIL PROTECTED] wrote:

  Though I'd like to be able to cast these arrays to PHP's arrays and we need
 to implement get_properties() handler for that.
  If there are no objections, I'll commit my patch when I get back home (30th
 of June).

2-way conversion would be perfect ;)

-- 
Alexey Zakhlestin
http://blog.milkfarmsoft.com/

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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Stanislav Malyshev

Hi!

The Lua interpreter handles this by resolving variable references as 
they're made; someVariable1 is looked up in the closure's scope and 
not found, so the interpreter steps out one scope and looks for it 


You may get into a problem here - creator's scope may not exist when you 
execute the closure, and using caller's scope would be very unexpected - 
usually closures are intended to capture part of creating environment, 
not calling environment. It would also impose serious penalty if you 
just use undefined variable - you'd have to go through whole stack up to 
the top.


there, repeat as necessary. Once found outside the closure's scope, 
something similar to the proposed lexical keyword happens. Closures 


lexical in the proposal binds to creator's scope, not caller's scope, as 
I understood. Anyway, binding to caller's immediate scope doesn't seem 
that useful since you could just pass it as a parameter when calling.

--
Stanislav Malyshev, Zend Software Architect
[EMAIL PROTECTED]   http://www.zend.com/
(408)253-8829   MSN: [EMAIL PROTECTED]

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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Stanislav Malyshev

Hi!

First: My patch is quite non-intrusive, it only adds things in a few
places (new opcode, a few checks). If you only look at the non-generated


I think it falls into famous last words category. While I did not have 
time yet to look into the patch in the detail, I have hard time to 
believe patch creating wholly new concept in PHP, new opcodes, etc. 
would have zero impact. You have to consider at least the following: 
tests, documentation, how lexical interacts with other references 
(global? static? just variable passed by-ref?), how closure interacts 
with various reflection capabilities, how it works with bytecode caches, 
what happens with lifetimes of the variables saved in closures - 
especially implicit ones like $this, etc., etc. I know these questions 
can be answered, and maybe even easily answered, but I think they have 
to be answered without pressure of 5.3 release and commitment to the 
fixed API hanging over us.


I understand your urge to have it inside ASAP - if you didn't want it, 
you'd not gone through this effort to create it :) However, I still 
think we better not make 5.3 dependent on yet another new feature.
As for adoption - I think it would take a long time for off-the-shelf 
libraries and mainstream users to use this anyway, and for the hackers 
among us it will be available in development version pretty soon after 
5.3. I think if we would decide that every new feature anybody can think 
about should enter into 5.3 because it will be harder to adopt it 
otherwise, we'd never release 5.3 at all - look at the RFCs, we have a 
bunch of ideas already, and I'm sure there will be more. We need to 
release some time - what happened to that release often thing?


Please do not consider this to be opinion about (or against) the patch - 
I think the idea is good and from preliminary glance the implementation 
is very nice too, but IMHO we just can not have everything in one release.

--
Stanislav Malyshev, Zend Software Architect
[EMAIL PROTECTED]   http://www.zend.com/
(408)253-8829   MSN: [EMAIL PROTECTED]

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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Chris Stockton
Hello,

I am curious if is_callable will be able to detect these? Or do we need a
is_lamba, or is_function or something. You may have mentioned it but reading
through I did not notice. I am only curious how to know when someone passed
me one of these. Maybe a type hint would be nice too but that is a different
conversation I guess.

-Chris


Re: [PHP-DEV] FastArray, great addition

2008-06-18 Thread Antony Dovgal

On 18.06.2008 16:40, Alexey Zakhlestin wrote:

On 6/18/08, Antony Dovgal [EMAIL PROTECTED] wrote:


 Though I'd like to be able to cast these arrays to PHP's arrays and we need
to implement get_properties() handler for that.
 If there are no objections, I'll commit my patch when I get back home (30th
of June).


2-way conversion would be perfect ;)


There is no way to cast an array to an object of certain class, 
but it should not be a problem to add a function to convert array to fastarray.


Want to make a patch yourself?
Should be pretty easy to do, just don't forget to throw an exception on string 
key.

--
Wbr, 
Antony Dovgal


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



Re: [PHP-DEV] FastArray, great addition

2008-06-18 Thread Alexey Zakhlestin
On 6/18/08, Antony Dovgal [EMAIL PROTECTED] wrote:

  2-way conversion would be perfect ;)
 

  There is no way to cast an array to an object of certain class, but it
 should not be a problem to add a function to convert array to fastarray.

  Want to make a patch yourself?
  Should be pretty easy to do, just don't forget to throw an exception on
 string key.

I will give it a try

-- 
Alexey Zakhlestin
http://blog.milkfarmsoft.com/

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



Re: [PHP-DEV] FastArray, great addition

2008-06-18 Thread Etienne Kneuss
Hello,

On Wed, Jun 18, 2008 at 4:47 PM, Antony Dovgal [EMAIL PROTECTED] wrote:
 On 18.06.2008 16:40, Alexey Zakhlestin wrote:

 On 6/18/08, Antony Dovgal [EMAIL PROTECTED] wrote:

  Though I'd like to be able to cast these arrays to PHP's arrays and we
 need
 to implement get_properties() handler for that.
  If there are no objections, I'll commit my patch when I get back home
 (30th
 of June).

 2-way conversion would be perfect ;)

 There is no way to cast an array to an object of certain class, but it
 should not be a problem to add a function to convert array to fastarray.

 Want to make a patch yourself?
 Should be pretty easy to do, just don't forget to throw an exception on
 string key.

I'll take care of it (both conversions actually)

Regards


 --
 Wbr, Antony Dovgal





-- 
Etienne Kneuss
http://www.colder.ch

Men never do evil so completely and cheerfully as
when they do it from a religious conviction.
-- Pascal

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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Gwynne Raskind

On Jun 18, 2008, at 11:01 AM, Stanislav Malyshev wrote:
The Lua interpreter handles this by resolving variable references  
as they're made; someVariable1 is looked up in the closure's  
scope and not found, so the interpreter steps out one scope and  
looks for it
You may get into a problem here - creator's scope may not exist when  
you execute the closure, and using caller's scope would be very  
unexpected - usually closures are intended to capture part of  
creating environment, not calling environment. It would also impose  
serious penalty if you just use undefined variable - you'd have to  
go through whole stack up to the top.


This lookup happens at the time the closure is first declared, and the  
value is stored for later use by the closure; the calling scope  
doesn't need to exist anymore. The problem with going to the top of  
the stack is an issue, though; the Lua interpreter's idea of scope  
is rather different from PHPs, and it's not nearly the same penalty  
there.





-- Gwynne, Daughter of the Code
This whole world is an asylum for the incurable.




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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Christian Seiler

Hi,

[I'm going to collect here a bit:]

Stanislav Malyshev wrote:
lexical in the proposal binds to creator's scope, not caller's scope, as 
I understood. Anyway, binding to caller's immediate scope doesn't seem 
that useful since you could just pass it as a parameter when calling.


Correct and I completely agree.

Chris Stockton wrote:

I am curious if is_callable will be able to detect these?


Yes, as is call_user_func able to call them. (But as I was verifying
that I saw that there was a tiny bug in the code that makes sure the
internal names are not used directly, I will fix that.)

Richard Quadling wrote:

[JS Example]

I'm not sure I would say that there is a reference used there.

I'm no expert, but x, f() and n are all working like normal variables with x
having to look outside of f().

Unless I'm getting confused with pass by reference.


Yes, shure, ok, it's not a reference in the classical sense BUT the
effect is the same: A change INSIDE the closure changes the variable
outside. The only useful way of doing that in PHP without rewriting the
complete engine is using references - and such things are *already* done
via references - namely global variables: If you import a variable via
$global, in reality you are creating a reference to the actual global
variable - global $foo is actually more or less the same as $foo =
$_GLOBALS['foo'].

Regards,
Christian

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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Stanislav Malyshev

Hi!

This lookup happens at the time the closure is first declared, and the 
value is stored for later use by the closure; the calling scope doesn't 


This would work for $var, but what about $$var and various other ways of 
indirect variable access?

--
Stanislav Malyshev, Zend Software Architect
[EMAIL PROTECTED]   http://www.zend.com/
(408)253-8829   MSN: [EMAIL PROTECTED]

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



Re: [PHP-DEV] [PATCH] getting current request's response code

2008-06-18 Thread Stanislav Malyshev

Hi!


Any interest in the attached patch? It introduces a
headers_response_code() function which returns


I see no problem with it. Just don't forget to add docs and test if you 
add it :)

--
Stanislav Malyshev, Zend Software Architect
[EMAIL PROTECTED]   http://www.zend.com/
(408)253-8829   MSN: [EMAIL PROTECTED]

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



RE: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Andi Gutmans
Hi Christian,

Thanks for the clarifications. This helped a lot and makes me feel very 
confident about this implementation. I think this is a very strong proposal.

A few additional things I thought about while taking a closer look:
- You mention global and static as examples of how we do things today. They 
are actually not good examples because the binding by reference which they do 
has been a real pain over the years. This is why we introduced the $GLOBALS[] 
array so that you could also assign by reference ($GLOBALS[foo] = $var). Now 
that I think of this example I'd actually prefer to see $LEXICALS[] or 
something similar to access variables then go with the broken global/static 
behavior. This will bite us and people will complain... In general, I always 
recommend to people to keep away from global and go with $GLOBALS[].
- Minor implementation suggestion: I am not sure we need those flags for 
closures and have those if() statements before function calls. We took the same 
approach with other obfuscated functions/methods/variables. If the developer 
*really* wants to cheat the engine and assemble an obfuscated name then he can. 
It's like doing the following in C: ((fun(*)()) 0x454544)(). I say, be my 
guest. It just simplifies implementation a bit. No biggy but consistent with 
the rest of PHP.
- Please check eval(). I assume it will bind to global scope but let's just 
make sure what happens esp. when it's called from within a method...
- In PHP 5, object storage is resources done right. I don't think we should be 
using the resource infrastructure for this implementation and would prefer to 
use the object one. It's better. I suggest to take a look at it.

Will also look into byte code cache implementation issues incl. performance 
pieces but it looks like there shouldn't be any show stoppers here but I want 
to verify.

Thanks again for your hard work!

Andi


Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Stanislav Malyshev

Hi!


by reference ($GLOBALS[foo] = $var). Now that I think of this
example I'd actually prefer to see $LEXICALS[] or something similar


The problem here might be that if we do something like $LEX[$foo] in 
runtime, we don't know which parts of parent's scope we need to 
preserve. While I like the syntax, it may not work this way.


Which brings me to another point - how bad would it be if closure's 
lifetime would be limited to parent's lifetime? Of course, this would 
limit some tricks, but would allow some other - like this direct access 
to parent's scope.



- Minor implementation suggestion: I am not sure we need those flags
for closures and have those if() statements before function calls. We


In any case I think we don't need to waste 2 bytes (or more with 
alignment) on something that's essentially 2 bits. I know it's 
nitpicking, but every little bit helps :) Of course, if we drop the 
flags the point is moot.

--
Stanislav Malyshev, Zend Software Architect
[EMAIL PROTECTED]   http://www.zend.com/
(408)253-8829   MSN: [EMAIL PROTECTED]

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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Alexey Zakhlestin
On 6/18/08, Stanislav Malyshev [EMAIL PROTECTED] wrote:

  Which brings me to another point - how bad would it be if closure's
 lifetime would be limited to parent's lifetime? Of course, this would limit
 some tricks, but would allow some other - like this direct access to
 parent's scope.

that would be seriously bad, because it will eliminate possibility of
lambda-generating functions


-- 
Alexey Zakhlestin
http://blog.milkfarmsoft.com/

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



Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP

2008-06-18 Thread Christian Seiler

Hi Andi, Hi Stanislav,


- You mention global and static as examples of how we do things
today. They are actually not good examples because the binding by
reference which they do has been a real pain over the years. This
is why we introduced the $GLOBALS[] array so that you could also
assign by reference ($GLOBALS[foo] = $var). Now that I think of
this example I'd actually prefer to see $LEXICALS[] or something
similar to access variables then go with the broken global/static
behavior. This will bite us and people will complain... In general,
I always recommend to people to keep away from global and go with
$GLOBALS[].



The problem here might be that if we do something like $LEX[$foo] in
runtime, we don't know which parts of parent's scope we need to
preserve. While I like the syntax, it may not work this way.


Yes, that's the point. 'lexical $foo' does two things (instead of global
simply doing one thing):

 a) At compile time (!) remember the name of the variable specified
in an internal list assigned to the function. Example:

function () {
  lexical $data, $i;
}

This will cause op_array-lexical_names to be the list data, i.

 b) At run time, the lexical keyword creates a reference to the
lexical variables that are stored in op_array-lexical_variables
(just as global does with global scope)

The op_array-lexical_variables itself is filled in the new opcode which
is executed upon *assignment* (read: creation) of the closure. It's
essentially a for loop that goes through op_array-lexical_names and
adds a reference from the current symbol table to the
op_array-lexical_variables table.

So, to make an example (with line numbers for reference):

1   $data = foo;
2   $i = 4;
3   $func = function () {
4 lexical $data, $i;
5 return array ($data, $i);
6   };
7
8   $func ();

Step 1 (Line 4 at compile time): op_array-lexical_names is set to
data, i.

Step 2 (Line 3 at run time): The ZEND_DECLARE_LAMBDA_FUNC opcode is
executed, it creates a copy of the op_array to store in the return
value, in the copy it initializes the hash table
op_array-lexical_variables and then creates two new variables in
op_array-lexical_variables which are references to the current scope
varialbes $data and $i:

 +---+  +-+
 | lex_variables |  | EG(active_symbol_table) |
 +---+  ref +-+
 | data--|--|- data  |
 | i   --|--|- i |
 |   |  |   func  |
 |   |  |   ...   |
 +---+  +-+

Step 3 (Line 8 at run time): The closure is executed.

Step 4 (Line 4 at run time): The lexical keyword retrieves the $data and
$i variables from op_array-lexical_variables and adds a reference to
them:

 +-+  +---+  +-+
 | EG(active_symbol_table) |  | lex_variables |  | parent s.t. |
 +-+  +---+  +-+
 | data|--|- data ---|--|- data  |
 | i   |--|- i---|--|- i |
 | |  |   |  |   func  |
 | |  |   |  |   ...   |
 +-+  +---+  +-+

Btw: The grammar for lexical_variable contains only T_VARIABLE (and not
${...} etc.) on purpose - to be sure the name can be extracted at
compile time.

(Just as a clarification how the patch internally works.)

Frankly, I don't really see a problem with using references. It fits
into what's already there in PHP and it assures that closures have the
necessary properties to make them useful.


Which brings me to another point - how bad would it be if closure's
lifetime would be limited to parent's lifetime? Of course, this would
limit some tricks, but would allow some other - like this direct
access to parent's scope.


That trick would actually completely destroy the concept of closures:
The idea behind closures is that the lexical scope during *creation* of
the closure is saved. If you say I want direct access via $LEXICALS
then the lexical scope during the *execution* of the closure will be
used (yeah sure, the scope will be the scope during the creation of the
closure but the *state* of that scope will be the scope during execution
and not creation - unbinding variables after defining the closure (and
therefore for example loops) will not be possible at that point).

Furthermore, the idea that the closure lives longer than the scope in
which it was declared is one of the other most basic ideas behind
closures. Also, consider this code:

function foo () {
  $lambda = function () { echo Hello World!\n; };
  $lambda 

[PHP-DEV] [PATCH] unix path separators in spl

2008-06-18 Thread Steph Fox

Hi all,

In Phar we have an internal Windows-only function named 
phar_unixify_path_separators(), which is needed because Phar is intended to 
be used with web apps.


Phar inherits from SPL, which currently uses the system-specific 
DEFAULT_SLASH when returning directory paths. This isn't actually a problem 
in Phar (at least, as far as I'm aware) but it does look... well, untidy.


The attached patch implements spl_unixify_path_separators(). If it's 
accepted, we can probably kill the version in Phar and rely on the 
definition in SPL. However I'm concerned that some other extension might be 
relying on SPL's current behaviour, unlikely tho' it may seem.


I haven't found any change in behaviour running the test suite for: ext/spl, 
ext/phar, ext/standard/array, ext/simplexml. I haven't tested: ext/pdo, 
ext/sqlite, ext/mysqli or pecl/spl_types, and I'm not certain if there 
should be any more on that list.


If you find/can see any problems with this change at all, pls adv. If there 
are no objections, I plan to commit at the end of this week.


Thanks,

- Steph 

Index: ext/spl/spl_directory.c
===
RCS file: /repository/php-src/ext/spl/spl_directory.c,v
retrieving revision 1.45.2.27.2.23.2.22
diff -u -r1.45.2.27.2.23.2.22 spl_directory.c
--- ext/spl/spl_directory.c 18 Jun 2008 10:05:29 -  
1.45.2.27.2.23.2.22
+++ ext/spl/spl_directory.c 18 Jun 2008 17:16:39 -
@@ -185,6 +185,9 @@
intern-file_name_len = spprintf(intern-file_name, 0, 
%s%c%s,
 
spl_filesystem_object_get_path(intern, NULL TSRMLS_CC),
 DEFAULT_SLASH, 
intern-u.dir.entry.d_name);
+#ifdef PHP_WIN32
+   spl_unixify_path_separators(intern-file_name, 
intern-file_name_len);
+#endif
break;
}
}
@@ -1196,6 +1199,9 @@
subdir-u.dir.sub_path_len = 
strlen(intern-u.dir.entry.d_name);
subdir-u.dir.sub_path = 
estrndup(intern-u.dir.entry.d_name, subdir-u.dir.sub_path_len);
}
+#ifdef PHP_WIN32
+   spl_unixify_path_separators(intern-u.dir.sub_path, 
intern-u.dir.sub_path_len);
+#endif
subdir-info_class = intern-info_class;
subdir-file_class = intern-file_class;
subdir-oth = intern-oth;
@@ -1227,6 +1233,9 @@

if (intern-u.dir.sub_path) {
len = spprintf(sub_name, 0, %s%c%s, intern-u.dir.sub_path, 
DEFAULT_SLASH, intern-u.dir.entry.d_name);
+#ifdef PHP_WIN32
+   spl_unixify_path_separators(sub_name, len);
+#endif
RETURN_STRINGL(sub_name, len, 0);
} else {
RETURN_STRING(intern-u.dir.entry.d_name, 1);
Index: ext/spl/spl_directory.h
===
RCS file: /repository/php-src/ext/spl/spl_directory.h,v
retrieving revision 1.12.2.5.2.4.2.10
diff -u -r1.12.2.5.2.4.2.10 spl_directory.h
--- ext/spl/spl_directory.h 20 May 2008 21:46:50 -  
1.12.2.5.2.4.2.10
+++ ext/spl/spl_directory.h 18 Jun 2008 17:10:18 -
@@ -112,6 +112,20 @@
return (spl_filesystem_object*)((char*)it - 
XtOffsetOf(spl_filesystem_object, it));
}

+#ifdef PHP_WIN32
+static inline void spl_unixify_path_separators(char *path, int path_len)
+{
+   char *s;
+
+   /* unixify win paths */
+   for (s = path; s - path  path_len; ++s) {
+   if (*s == '\\') {
+   *s = '/';
+   }
+   }
+}
+#endif
+
#define SPL_FILE_OBJECT_DROP_NEW_LINE  0x0001 /* drop new lines */
#define SPL_FILE_OBJECT_READ_AHEAD 0x0002 /* read on rewind/next */
#define SPL_FILE_OBJECT_SKIP_EMPTY 0x0006 /* skip empty lines */

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

Re: [PHP-DEV] [PATCH] make it possible to skip very slow tests

2008-06-18 Thread Stanislav Malyshev

Hi!


+$environment['EXEMPT_SLOW_TESTS'] = 1;


Maybe SKIP_SLOW_TESTS? If it's checked in skip section... :)
Otherwise - good idea!
--
Stanislav Malyshev, Zend Software Architect
[EMAIL PROTECTED]   http://www.zend.com/
(408)253-8829   MSN: [EMAIL PROTECTED]

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



Re: [PHP-DEV] [PATCH] make it possible to skip very slow tests

2008-06-18 Thread Travis Swicegood

Hey Steph;

On Jun 18, 2008, at 3:37 PM, Steph Fox wrote:

I'm using this locally because two of our tests take over 10  
minutes each to run on my laptop, and I run the relevant bits of  
test suite every time I make a change.


All it does is adds another option, -x, to run-tests.php. This sets  
an environmental variable which can then be checked for in the  
SKIPIF section of very slow-running tests.


How do you specify that test A is slow?  Is there a certain skipif  
message you include, or...?


-T

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



Re: [PHP-DEV] [RFC] Strict type hints (parameter and return value)

2008-06-18 Thread Fabrice VIGNALS


In mathematic, equal meen the same value AND the same nature.
The follow fact could be frustrating :

Code :
? php echo 'you must understand than 1 + 1 = 2' ?
Output :
you must understand than 2 = 2


- Original Message - 
From: Stanislav Malyshev [EMAIL PROTECTED]

To: Chris Stockton [EMAIL PROTECTED]
Cc: internals@lists.php.net
Sent: Monday, June 16, 2008 11:02 PM
Subject: Re: [PHP-DEV] [RFC] Strict type hints (parameter and return value)



Hi!


Maybe we should stop using the 1 and '1' argument, yes, they can be


Maybe not, while there are people that fail to understand it. Here:


But try to remember, 1 !== '1' and PHP is not an end all language, often
we have to communicate to strictly type systems, we need to be positive


So you just ignored the special cases part. Yes, if you have special
case where you interface with very brain-dead strictly typed system that
absolutely can't understand that '1' and 1 is the same - then you need
to _convert_. So how failing when you get '1' instead of 1 helps you?
You'd need _conversion_, not _failure_ - and if you write strictly-typed
API, you'd move the conversion responsibility to the user, instead of
having it where it belongs - in the API. That's *exactly* why I see
strict typing in PHP so dangerous - it promotes lazyness and sloppiness
in API writing, and those APIs will be a nightmare to use, since they
would bomb out on slightest disagreement about internal engine types,
which the API user shouldn't care about at all. What happened with be
liberal at what you accept?
In strict compiled languages, the compiler and IDE will guide you
through this, in PHP you'd just have it explode in your face in
production. How this is good for anybody?
--
Stanislav Malyshev, Zend Software Architect
[EMAIL PROTECTED]   http://www.zend.com/
(408)253-8829   MSN: [EMAIL PROTECTED]


--
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] deprecation status of $str{42} versus $str[42]

2008-06-18 Thread Andrei Zmievski
Maybe TextIterator can be backported from HEAD, because it allows for 
just that.


foreach (new TextIterator($str) as $c) {
  ...
}

Arvids Godjuks wrote:

2008/6/16 Edward Z. Yang [EMAIL PROTECTED]:


PHP userland code may not treat strings as first class arrays, but
that's certainly how they are represented internally.

Anyway, it would be neat if we could get that foreach syntax to work. I
get sick of for($i = 0, $c = strlen($str); $i  $c; $i++) very quickly.



Totaly agree, the best example from the whole thread



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



Re: [PHP-DEV] deprecation status of $str{42} versus $str[42]

2008-06-18 Thread Stanislav Malyshev

Hi!

Maybe TextIterator can be backported from HEAD, because it allows for 
just that.


foreach (new TextIterator($str) as $c) {
  ...
}


That'd be a nice addition to intl extension, too - if we implement all 
functionality. Any volonteers? :)
Problem there would be that it would be somewhat slower - characters 
would have to be converted from Unicode to UTF-8 on each cycle - if we 
use ICU iterators (not necessary for simple cases I guess). But having 
it in 5.x would help some people, I guess.

--
Stanislav Malyshev, Zend Software Architect
[EMAIL PROTECTED]   http://www.zend.com/
(408)253-8829   MSN: [EMAIL PROTECTED]

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



Re: [PHP-DEV] deprecation status of $str{42} versus $str[42]

2008-06-18 Thread Edward Z. Yang
Andrei Zmievski wrote:
 Maybe TextIterator can be backported from HEAD, because it allows for
 just that.
 
 foreach (new TextIterator($str) as $c) {
   ...
 }

IIRC, TextIterator is specifically designed for Unicode, letting you
iterate over codepoints, combining sequences, characters, words, etc. So
making it do all that would only make sense with intl, and even then not
really (as Stanislav points out performance-wise).

What I was suggesting was a shortcut to iterating over binary data; i.e.
byte by byte.

-- 
 Edward Z. YangGnuPG: 0x869C48DA
 HTML Purifier http://htmlpurifier.org Anti-XSS Filter
 [[ 3FA8 E9A9 7385 B691 A6FC B3CB A933 BE7D 869C 48DA ]]

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



Re: [PHP-DEV] [RFC] Strict type hints (parameter and return value)

2008-06-18 Thread Edward Z. Yang
Fabrice VIGNALS wrote:
 In mathematic, equal meen the same value AND the same nature.
 The follow fact could be frustrating :

Usually, context is good enough to disambiguate between the cases. The
most prevalent convention in programming languages is = is assignment,
and == is comparison (PHP adds === only because of its type-juggling
system). Other languages have = as comparison, and := as assignment.
Donald Knuth uses = as comparison, and a left arrow (-) for assignment.

-- 
 Edward Z. YangGnuPG: 0x869C48DA
 HTML Purifier http://htmlpurifier.org Anti-XSS Filter
 [[ 3FA8 E9A9 7385 B691 A6FC B3CB A933 BE7D 869C 48DA ]]

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



Re: [PHP-DEV] deprecation status of $str{42} versus $str[42]

2008-06-18 Thread Andrei Zmievski
Yes, and we can have TextIterator work on binary strings as well 
(perhaps by adding TextIterator::BYTE constant).


-Andrei

Edward Z. Yang wrote:

Andrei Zmievski wrote:

Maybe TextIterator can be backported from HEAD, because it allows for
just that.

foreach (new TextIterator($str) as $c) {
  ...
}


IIRC, TextIterator is specifically designed for Unicode, letting you
iterate over codepoints, combining sequences, characters, words, etc. So
making it do all that would only make sense with intl, and even then not
really (as Stanislav points out performance-wise).

What I was suggesting was a shortcut to iterating over binary data; i.e.
byte by byte.



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



Re: [PHP-DEV] [PATCH] make it possible to skip very slow tests

2008-06-18 Thread Christopher Jones



Steph Fox wrote:

Hi again,

I'm using this locally because two of our tests take over 10 minutes 
each to run on my laptop, and I run the relevant bits of test suite 
every time I make a change.


All it does is adds another option, -x, to run-tests.php. This sets an 
environmental variable which can then be checked for in the SKIPIF 
section of very slow-running tests.


Any objections if I commit it in 5_3/HEAD?


I'd prefer a run-tests.php option that sets the timeout limit in seconds.

Chris

--
Christopher Jones, Oracle
Email: [EMAIL PROTECTED]Tel:  +1 650 506 8630
Blog:  http://blogs.oracle.com/opal/   Free PHP Book: http://tinyurl.com/f8jad

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