Stut wrote:
> Colin Guthrie wrote:
>> Stut wrote:
>>> Colin Guthrie wrote:
>>>> Stut wrote:
>>>>> Stut wrote:
>>>>>> In that case you need a new foo. That's the only way you're going to
>>>>>> reset the internal static if the API doesn't give you a way to do it.
>>>>>>
>>>>>> $f=new foo();
>>>>>> $f->bar();
>>>>>> $f->bar();
>>>>>> $g=new foo();
>>>>>> $g->bar();
>>>>> Actually, scratch that, won't work. Not even unsetting $f before
>>>>> creating the new object works. This kinda sucks since it means PHP
>>>>> does
>>>>> not support static function-scoped vars.
>>>> Yeah I tried that same thing too and then wondered if I had
>>>> misinterpreted how function-scoped statics worked.
>>>>
>>>> I've often used a method like:
>>>>
>>>> function Init()
>>>> {
>>>> static $bln_inited = false;
>>>> if (!$bln_inited)
>>>> {
>>>> // Do stuff
>>>> $bln_inited = true;
>>>> }
>>>> }
>>>>
>>>>
>>>> I had always assumed that the static definition here was
>>>> function-scoped... I guess I should have tested more but still it
>>>> caught
>>>> me off guard this morning when I played with it.
>>>>
>>>> Correct me if I'm wrong but does C++ not do it as both of us initially
>>>> thought? e.g. static is function scoped rather than globally scoped
>>>> when
>>>> used within a class method?
>>> Yes it does, which is why I assumed PHP would do it like that too. I
>>> knew I should have tried it before sending the reply.
>>>
>>> I've tried various ways of accessing that variable via a derived class
>>> but it doesn't seem to be possible. Again I'm just assuming, but my
>>> theory is that the line...
>>>
>>> static $foobar = false;
>>>
>>> ...actually is static to the function and therefore cannot be accessed
>>> from outside it in any way, shape or form.
>>>
>>> So using function statics as you have above will work fine. And they
>>> also work fine when used in a method of a class. This behaviour is
>>> correct because if a function-scoped static is to work correctly there
>>> should be absolutely no way to get at it from outside the function.
>>
>> I completely agree that there should be no way to access it outside the
>> function/method it is defined within. The problem is that in PHP the
>> static keyword seems to be globally unique but function/class scoped.
>> e.g. that if it is used in a class method, regardless of how many
>> instances of that method you create with "new" there is only ever one
>> "instance" of the variable.
>>
>> So the case where it wont work fine is when you have the above function
>> as a method of a class which can have multiple instances, all of which
>> need to be Init()'ed independently.
>>
>> In such cases, I guess you'd have to use a private member variable
>> instead which just isn't quite a neat and tidy.
>>
>> If you only ever have one instance of the class then all is well but
>> still could have unexpected side effects if you later extend the system
>> to have more than one instance. I guess if you use a singltron method
>> with a private constructor then it's safe enough but then you can just
>> do your initialisation in the singletron method in that case so there's
>> little point!
>>
>> Hey ho.
>>
>> /me scuttles of to grep code for "static" :s
>
> Nope, not globally unique: http://dev.stut.net/php/funcstatic.php
>
> So what you have will be fine.
No it wont work as I *intended* but that is purely due to my own
misinterpretation of how statics in a method works.
I've satisfied my own understanding now by testing it in C++ and it
behaves the same as in PHP here, so I'm completely in the know (now!).
I did however think it worked differently! Like I say it's just my own
misunderstanding.
Here is what I meant for completeness:
Try the following code and note especially the last two lines of the
output (change the \n to <br /> if you want if for web output.. I tested
on cmdline).
<?php
$GLOBALS['eol'] = "\n";
class c
{
public function a($nm)
{
static $var = 0;
print $nm.'a: '.$var.$GLOBALS['eol'];
$var++;
}
public function b($nm)
{
static $var = 0;
print $nm.'b: '.$var.$GLOBALS['eol'];
$var++;
}
}
$c = new c();
for ($i = 0; $i < 10; $i++)
{
$c->a('C');
if ($i % 2)
$c->b('C');
}
$d = new c();
$d->a('D');
$d->b('D');
?>
Ca: 0
Ca: 1
Cb: 0
Ca: 2
Ca: 3
Cb: 1
Ca: 4
Ca: 5
Cb: 2
Ca: 6
Ca: 7
Cb: 3
Ca: 8
Ca: 9
Cb: 4
Da: 10
Db: 5
i.e. the $d object just carries on where $c left off. This is not what I
had in my head how things worked.
I had originally thought that the static keyword within a class method
was only static in the context of that *instance* of the class. This is
clearly mince now I look into it and think about it a bit.
e.g. consider the following class.
<?php
$GLOBALS['eol'] = "\n";
class foo
{
private $mVar = "Uninitialised";
public function Init()
{
static $bln_initialised = false;
if (!$bln_initialised)
{
$this->mVar = 'Initialised';
$bln_initialised = true;
}
}
public function Display($nm)
{
echo $nm.': '.$this->mVar.$GLOBALS['eol'];
}
}
$foo = new foo();
$foo->Init();
$foo->Display('Foo');
$bar = new foo();
$bar->Init();
$bar->Display('Bar');
?>
Foo: Initialised
Bar: Uninitialised
That's not what I *wanted* to happen, even tho' I now understand that's
what *should* happen!
I confirmed this with C++ to satisfy me that that's what it does too and
it does:
#include <iostream>
#include <string>
using namespace std;
class foo
{
public:
foo();
void Init();
void Display(string nm);
private:
string var;
};
foo::foo()
:var("Uninitialised")
{
}
void foo::Init()
{
static bool bln_initialised = false;
if (!bln_initialised)
{
var = "Initialised";
bln_initialised = true;
}
}
void foo::Display(string nm)
{
cout << nm << ": " << var << endl;
}
int main()
{
foo foo, bar;
foo.Init();
foo.Display("Foo");
bar.Init();
bar.Display("Bar");
return 0;
}
Foo: Initialised
Bar: Uninitialised
So my understanding suitably updated. :)
Col
PS I know the above examples are contrived and that constructors would
be more appropriate for the above - but using constructors is not always
possible due to how you deal with failed initialisations where
exceptions are not desirable.
--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php