php-general Digest 16 Aug 2012 06:38:11 -0000 Issue 7924

Topics (messages 318706 through 318716):

Re: Reading class variable value always returns NULL
        318706 by: Reto Kaiser
        318707 by: Philipp Gysin

Re: Two ways to obtain an object property
        318708 by: Paul M Foster
        318709 by: Andrew Ballard
        318711 by: David Harkness
        318716 by: Mihamina Rakotomandimby

Re: PHP session variables
        318710 by: Andrew Ballard
        318712 by: Tedd Sperling
        318713 by: Tedd Sperling
        318714 by: Robert Cummings
        318715 by: Andrew Ballard

Administrivia:

To subscribe to the digest, e-mail:
        php-general-digest-subscr...@lists.php.net

To unsubscribe from the digest, e-mail:
        php-general-digest-unsubscr...@lists.php.net

To post to the list, e-mail:
        php-gene...@lists.php.net


----------------------------------------------------------------------
--- Begin Message ---
So here's some new observations on the instance variables being NULL.
As far as we found out this is the sequence of events:

1. Apache (MPM) received request A which executes a php script.
2. Within this script during the unserialization of an object an
exception is thrown.
3. This exception is catched and an error message is display to
standard output with "echo".
4. The script ends normally and the standard output contents are
returned in the HTTP response.
5. From now on this Apache worker is "tainted", meaning that every
subsequent request will result in:

6. The same apache worker receives request B which executes a PHP script.
7. Within this PHP script reading instance variables will always
return NULL, e.g.:

<?php
class A{}
$a = new A();
$a->foo = 1;
// Now: $a->foo === NULL

All subsequent requests to this apache worker will behave like this.
The constellation leading to this behavior is very hard to further
simplify. If we throw different exceptions, or unserialize different
objects it doesn't happen anymore...


As a workaround we added "exit;" to the end of our php script. With a
call to "exit" the apache worker will not get "tainted"...

Regards,
 Reto



On Tue, Aug 14, 2012 at 11:52 PM, Reto Kaiser <r...@cargomedia.ch> wrote:
> Hey,
>
> We have:
> error_reporting((E_ALL | E_STRICT) & ~(E_NOTICE | E_USER_NOTICE));
>
> Displaying errors is disabled:
> display_errors = Off
>
> We have a custom error handler which logs all errors to a file.
> In this file we receive byeffect errors, like that the second argument
> to "array_key_exists" should be array, but is NULL. When we further
> debug the reason is that the second argument is an instance variable,
> and all instance variables are NULL.
> We're pretty sure this is a software bug, since it only happens from
> time to time, and already happens in the first line of the php script,
> when none of our application code was loaded.
> For example:
>
> <?php
> class A{}
> $a = new A();
> $a->foo = 1;
> if ($a->foo === null) {
>  throw new Exception("strange");
> }
>
> will throw an exception.
>
> Since it only happens from time to time, it is really hard to debug.
> We're now trying to reproduce in a virtual machine environment, while
> replaying the actual requests that our webserver received. When we're
> just simulating random load on the web server it doesn't happen. So it
> must have something to do with certain requests, and they must have
> some strange byeffect on php, or mod_php or something related.
>
> Any input welcome!
>
> Thanks,
>  Reto
>
> On Tue, Aug 14, 2012 at 11:11 PM, Jim Lucas <li...@cmsws.com> wrote:
>> On 08/12/2012 05:32 AM, Reto Kaiser wrote:
>>>
>>> Hi,
>>>
>>> So I have this strange situation where I assign a classvariable a
>>> value, but when I read the value it is NULL.
>>>
>>> Does anyone have an idea what could cause this, or how to further debug?
>>>
>>> Thanks,
>>>   Reto
>>>
>>
>> What is your error reporting set to?
>>
>> Do you have display errors turned on?
>>
>> Are you saving your errors to a log file?
>>
>> --
>> Jim Lucas
>>
>> http://www.cmsws.com/
>> http://www.cmsws.com/examples/

--- End Message ---
--- Begin Message ---
As a little clarification: The Apache server in question is configured as a
MPM prefork.


On Wed, Aug 15, 2012 at 4:28 PM, Reto Kaiser <r...@cargomedia.ch> wrote:

> So here's some new observations on the instance variables being NULL.
> As far as we found out this is the sequence of events:
>
> 1. Apache (MPM) received request A which executes a php script.
> 2. Within this script during the unserialization of an object an
> exception is thrown.
> 3. This exception is catched and an error message is display to
> standard output with "echo".
> 4. The script ends normally and the standard output contents are
> returned in the HTTP response.
> 5. From now on this Apache worker is "tainted", meaning that every
> subsequent request will result in:
>
> 6. The same apache worker receives request B which executes a PHP script.
> 7. Within this PHP script reading instance variables will always
> return NULL, e.g.:
>
> <?php
> class A{}
> $a = new A();
> $a->foo = 1;
> // Now: $a->foo === NULL
>
> All subsequent requests to this apache worker will behave like this.
> The constellation leading to this behavior is very hard to further
> simplify. If we throw different exceptions, or unserialize different
> objects it doesn't happen anymore...
>
>
> As a workaround we added "exit;" to the end of our php script. With a
> call to "exit" the apache worker will not get "tainted"...
>
> Regards,
>  Reto
>
>
>
> On Tue, Aug 14, 2012 at 11:52 PM, Reto Kaiser <r...@cargomedia.ch> wrote:
> > Hey,
> >
> > We have:
> > error_reporting((E_ALL | E_STRICT) & ~(E_NOTICE | E_USER_NOTICE));
> >
> > Displaying errors is disabled:
> > display_errors = Off
> >
> > We have a custom error handler which logs all errors to a file.
> > In this file we receive byeffect errors, like that the second argument
> > to "array_key_exists" should be array, but is NULL. When we further
> > debug the reason is that the second argument is an instance variable,
> > and all instance variables are NULL.
> > We're pretty sure this is a software bug, since it only happens from
> > time to time, and already happens in the first line of the php script,
> > when none of our application code was loaded.
> > For example:
> >
> > <?php
> > class A{}
> > $a = new A();
> > $a->foo = 1;
> > if ($a->foo === null) {
> >  throw new Exception("strange");
> > }
> >
> > will throw an exception.
> >
> > Since it only happens from time to time, it is really hard to debug.
> > We're now trying to reproduce in a virtual machine environment, while
> > replaying the actual requests that our webserver received. When we're
> > just simulating random load on the web server it doesn't happen. So it
> > must have something to do with certain requests, and they must have
> > some strange byeffect on php, or mod_php or something related.
> >
> > Any input welcome!
> >
> > Thanks,
> >  Reto
> >
> > On Tue, Aug 14, 2012 at 11:11 PM, Jim Lucas <li...@cmsws.com> wrote:
> >> On 08/12/2012 05:32 AM, Reto Kaiser wrote:
> >>>
> >>> Hi,
> >>>
> >>> So I have this strange situation where I assign a classvariable a
> >>> value, but when I read the value it is NULL.
> >>>
> >>> Does anyone have an idea what could cause this, or how to further
> debug?
> >>>
> >>> Thanks,
> >>>   Reto
> >>>
> >>
> >> What is your error reporting set to?
> >>
> >> Do you have display errors turned on?
> >>
> >> Are you saving your errors to a log file?
> >>
> >> --
> >> Jim Lucas
> >>
> >> http://www.cmsws.com/
> >> http://www.cmsws.com/examples/
>

--- End Message ---
--- Begin Message ---
On Wed, Aug 15, 2012 at 09:28:28AM +0100, phplist wrote:

> This relates to a minor dilemma I come across from time and time,
> and I'm looking for advice on pros and cons and best practice. Last
> night I encountered it again.
> 
> Within a site I have a User object, and within page code would like to have
> if ($crntUser->isASubscriber) {...}
> 
> There seems to be two ways to handle this:
> 
> I can have a User object method "getSubscriberStatus()" which sets
> $this->isASubscriber. But to use this I would have to run the method
> just before the if statement.
> 
> Or I could have a method "isASubscriber()" which returns the result,
> meaning the if statement should be
> if ($crntUser->isASubscriber()) {...}
> 
> While this is last night's specific example, I seem to face the
> method-setting-variable or the method-returning-result-directly
> decision quite often.
> 
> Is either of these approaches preferable, or does it simply not matter?

If I read you correctly, the latter would be preferable, primarily
because it involves one less step. But if you're going to have to make
that decision in an "if" statement repeatedly, I'd probably say:

$isSubscribed = $crntUser->isASubscriber();

just because in subsequent code, you're not suffering the (admittedly
small) repeated overhead of the function call.

But in answer to your question, isASubscriber() would be a pretty
standard "getter" method to expose internal object properties.

Paul

-- 
Paul M. Foster
http://noferblatz.com
http://quillandmouse.com

--- End Message ---
--- Begin Message ---
On Wed, Aug 15, 2012 at 11:33 AM, Paul M Foster <pa...@quillandmouse.com> wrote:
> On Wed, Aug 15, 2012 at 09:28:28AM +0100, phplist wrote:
>
>> This relates to a minor dilemma I come across from time and time,
>> and I'm looking for advice on pros and cons and best practice. Last
>> night I encountered it again.
>>
>> Within a site I have a User object, and within page code would like to have
>> if ($crntUser->isASubscriber) {...}
>>
>> There seems to be two ways to handle this:
>>
>> I can have a User object method "getSubscriberStatus()" which sets
>> $this->isASubscriber. But to use this I would have to run the method
>> just before the if statement.
>>
>> Or I could have a method "isASubscriber()" which returns the result,
>> meaning the if statement should be
>> if ($crntUser->isASubscriber()) {...}
>>
>> While this is last night's specific example, I seem to face the
>> method-setting-variable or the method-returning-result-directly
>> decision quite often.
>>
>> Is either of these approaches preferable, or does it simply not matter?
>
> If I read you correctly, the latter would be preferable, primarily
> because it involves one less step. But if you're going to have to make
> that decision in an "if" statement repeatedly, I'd probably say:
>
> $isSubscribed = $crntUser->isASubscriber();
>
> just because in subsequent code, you're not suffering the (admittedly
> small) repeated overhead of the function call.
>
> But in answer to your question, isASubscriber() would be a pretty
> standard "getter" method to expose internal object properties.
>
> Paul

I generally use this "getter" method as well. If it bothers the OP
that isASubscriber() is a "method" rather than a "property," one could
use the magic __get method:

<?php

class User
{
        private $isASubscriber = false;

        public function __get($property)
        {
                if ('isASubscriber' === $property) {
                        return $this->isASubscriber;
                }
        }
}

?>

In the end, it is still a function call either way though. The
advantage I see to both of these method-based approaches versus
exposing the property as public is that these methods prevent code
outside your class from doing something stupid:

<?php

$u = new User();

$u->isASubscriber = 'rutabaga';

// Fatal error: Cannot access private property User::$isASubscriber
?>

(Yes, I have seen proof that it is TECHNICALLY possible to get around
this in PHP, for example with unserialize.)

Andrew

--- End Message ---
--- Begin Message ---
On Wed, Aug 15, 2012 at 1:28 AM, phplist <phpl...@myword.co.uk> wrote:

> I can have a User object method "getSubscriberStatus()" which sets
> $this->isASubscriber. But to use this I would have to run the method just
> before the if statement.
>
> Or I could have a method "isASubscriber()" which returns the result,
> meaning the if statement should be
> if ($crntUser->isASubscriber()) {...}


I assume that the decision isn't really about using a property versus a
method but that determining the value of the property is costly. For these
cases I add an internal private property to save the result of the costly
computation and initialize it on the first call to the accessor method.

    class User {
        private $_isSubscriber = null;

        public function isSubscriber() {
            if ($this->_isSubscriber === null) {
                $this->_isSubscriber = ... call database or whatever takes
so long ...
            }
            return $this->_isSubscriber;
        }
    }

If this isn't the case and you really just want to know which API is nicer,
any of the replies so far are acceptable. I favor accessor methods because
it's easier to change the implementation without having to change all the
places you access it.

Peace,
David

--- End Message ---
--- Begin Message ---
On 08/15/2012 11:28 AM, phplist wrote:
This relates to a minor dilemma I come across from time and time, and
I'm looking for advice [...]

Within a site I have a User object, and within page code would like to have
if ($crntUser->isASubscriber) {...}
[...]
if ($crntUser->isASubscriber()) {...}
[...]
Is either of these approaches preferable, or does it simply not matter?


It depends
- how long/heavy is isASubscriber()
- how often you need to check
- how realtime you need the subscription status to be

if isASubscriber() is long/heavy (say you need to wait for a long query), I would suggest to set an attribute and get you information from the attribute.
Otherwise, you can safely use the method.

If you have "realtime" constraints, you have no choice than use the method, wether it's long or not.

Talking about "best practice", I would use:
- $currentUser->isSubscriber
- $currentUser->isSubscriber()
It's a naming matter.



--
RMA.

--- End Message ---
--- Begin Message ---
On Fri, Aug 10, 2012 at 11:56 AM, Tedd Sperling <t...@sperling.com> wrote:
> On Aug 10, 2012, at 11:45 AM, Tedd Sperling <t...@sperling.com> wrote:
>
>> On Aug 9, 2012, at 5:16 PM, Jim Lucas <li...@cmsws.com> wrote:
>>> You are relying on PHP's loose typing.  This is a poor check.
>>>
>>> session_id() returns a string, not boolean.
>>>
>>> You should do this instead.
>>>
>>> if ( session_id() === '' )
>>> ....
>>>
>>>
>>> --
>>> Jim Lucas
>>
>> Thanks Jim -- you're right.
>>
>> What about?
>>
>> if (!defined(SID))
>>       {
>>       session_start();
>>       }
>
> Before you answer, the "(!defined(SID))" is over 50 times slower than "( 
> session_id() === '' )"
>
> Your way is better.
>
> Cheers,
>
> tedd

tedd,

I think this is because you passed SID to defined() as a constant
rather than a string, so the if test always returns true. When I
changed this to

if (!defined('SID'))
    {
    session _start();
    }

it worked as expected, and I got much more similar results. I also
added a call to session_destroy() between the two tests so that each
loop initialized the session once. (In your test, the second loop
never initializes the session since it was already started by the
first loop.)

This is your code with my modifications:

<?php

      $starttime = microtime(true);


      // whatever you want timed, you do here.



      for($i=1; $i < 1000; $i++)
        {
        if (!defined('SID'))
          {
          echo __LINE__, '::session_start()<br>';
          session_start();
          }
        }

      session_destroy();

      $endtime = microtime(true);
      $totaltime = $endtime - $starttime;
      $totaltime = round($totaltime,5);
      echo "<p>First in $totaltime seconds.</p>";

      $starttime = microtime(true);


      // whatever you want timed, you do here.

      for($i=1; $i < 1000; $i++)
        {
        if (session_id() ==='')
          {
          echo __LINE__, '::session_start()<br>';
          session_start();
          }
        }

      $endtime = microtime(true);
      $totaltime = $endtime - $starttime;
      $totaltime = round($totaltime,5);
      echo "<p>Second in $totaltime seconds.</p>";

      session_destroy();

?>

Andrew

--- End Message ---
--- Begin Message ---
On Aug 14, 2012, at 11:01 AM, Robert Cummings <rob...@interjinn.com> wrote:
> 
> I'm not sure if you're making a joke, but your changes have no effect. You've 
> merely explicitly stated the optional parameter's default value. What I had 
> meant was to change the following:
> 
> <?php
> 
> $starttime = microtime();
> $startarray = explode(" ", $starttime);
> $starttime = $startarray[1] + $startarray[0];
> 
> ?>
> 
> To the following :)
> 
> <?php
> 
> $starttime = microtime( true );
> 
> ?>
> 
> Cheers,
> Rob.

Rob:

Again thanks.

Sorry, I totally missed your point.

In my "defense" I commonly use the value returned from microtime() as a string 
and not as a float. The code that followed my "microtime( false );" demo broke 
the string and recombined it into a float. So, when you said:

Please see the current signature for microtime():

   mixed microtime ([ bool $get_as_float = false ] )

I looked at that and said to myself, "Oh, I need to define it as 'false' " 
because I was using it as a sting. I completely overlooked your point that 
microtime() could return a float and thus no need to work with it as a string 
-- duh!

The demo is fixed (I think):

http://www.webbytedd.com/b/timed1/

Thanks,

tedd


_____________________
t...@sperling.com
http://sperling.com




--- End Message ---
--- Begin Message ---
Andrew:

Your points are well taken -- thanks.

However, my only concern is given this:

>      for($i=1; $i < 1000; $i++)
>        {
>        if (!defined('SID'))
>          {
>          echo __LINE__, '::session_start()<br>';
>          session_start();
>          }
>        }

The php manual ( http://us3.php.net/manual/en/function.session-start.php )

First Note states that session_start() must be called *before* anything sent to 
the Browser.

So, to rewrite your code --

     for($i=1; $i < 1000; $i++)
       {
       if (!defined('SID'))
         {
         session_start();
         echo __LINE__, '::session_start()<br>';
         }
       }

-- should work better, right?

Cheers,

tedd


_____________________
t...@sperling.com
http://sperling.com

--- End Message ---
--- Begin Message ---
On 12-08-15 03:19 PM, Tedd Sperling wrote:
Rob:

Again thanks.

Sorry, I totally missed your point.

In my "defense" I commonly use the value returned from microtime() as a string and not as 
a float. The code that followed my "microtime( false );" demo broke the string and 
recombined it into a float. So, when you said:

Please see the current signature for microtime():

    mixed microtime ([ bool $get_as_float = false ] )

I looked at that and said to myself, "Oh, I need to define it as 'false' " 
because I was using it as a sting. I completely overlooked your point that microtime() 
could return a float and thus no need to work with it as a string -- duh!

The demo is fixed (I think):

http://www.webbytedd.com/b/timed1/

Thanks,

tedd


I only pointed it out because I used to do exactly the same thing :)

Cheers,
Rob.
--
E-Mail Disclaimer: Information contained in this message and any
attached documents is considered confidential and legally protected.
This message is intended solely for the addressee(s). Disclosure,
copying, and distribution are prohibited unless authorized.

--- End Message ---
--- Begin Message ---
On Wed, Aug 15, 2012 at 3:24 PM, Tedd Sperling <t...@sperling.com> wrote:
> Your points are well taken -- thanks.

I've seen a lot of people code that way, so it's easy to miss. In your
original code, that first statement was calling session_start() 1,000
times. This is because the first time through, SID is undefined so
defined(SID) was equivalent to defined('SID') and both would have
returned false. After the first session_start(), though, SID WAS
defined, but would have had some pseudo-random session identifier as
its value. As a result, the last 999 times through your loop, you were
actually scanning the defined constants to see if there was one named
something like '7cjubadsh5lkq80opemht2ea03'. Obviously, it would never
exist.

> However, my only concern is given this:
>
>>      for($i=1; $i < 1000; $i++)
>>        {
>>        if (!defined('SID'))
>>          {
>>          echo __LINE__, '::session_start()<br>';
>>          session_start();
>>          }
>>        }
>
> The php manual ( http://us3.php.net/manual/en/function.session-start.php )
>
> First Note states that session_start() must be called *before* anything sent 
> to the Browser.
>
> So, to rewrite your code --
>
>      for($i=1; $i < 1000; $i++)
>        {
>        if (!defined('SID'))
>          {
>          session_start();
>          echo __LINE__, '::session_start()<br>';
>          }
>        }
>
> -- should work better, right?
>
> Cheers,
>
> tedd


Yes, that is more correct. I think we have output buffering enabled on
most of our servers (a lot of our legacy stuff really depends on it)
so I didn't notice any errors, but you are correct. You really don't
need the echo lines that I added in your test at all though. I just
threw it in there to be able to see when the function was being
called. However, due to the nature of your test page you are still
sending output from the first loop before you call session_start() in
the second loop. To be absolutely correct, you'd have to remove those
echo statements I added for debugging, store all of your timings in
separate variables and then output them at the end of the script.

Andrew

--- End Message ---

Reply via email to