Jump to content

Where am I being called from?


decioalex

Recommended Posts

Hi,

 

expanding a little on this post: http://www.phpfreaks.com/forums/index.php/topic,154922.0.html, I have a problem with knowing where my properties are being called from.

 

What I am trying to do is setting a way to declare strong typed fields within a class, and setting it as private, protected or public and as readonly, writeonly or both.

 

For this to work, I am using the __get and __set magic methods to receive the call for an unset property (with the same "base" name as the ones declared inside the class, and check if it should be pointing to a "strong typed" declared property. So far so good and everything is working perfectly.

 

The problem is that the __get and __set methods (expectedly) does not inform me if the call is being done from within the class, its children or from outside it, so I can't check for visibility.

 

That is why I am looking for a possible way to make sure from where that property was called, so I can trigger the visibility check methods.  ???

 

Any help is appreciated.

Thanks!  ;D

Link to comment
Share on other sites

AFAIK you can't. If you want to enforce visibility, then you'll have to declare it using e.g. public $whatever;.

 

Oh..  :'(

 

Isn't there any way to catch how or when PHP triggers the visibility check?

Or a way to know where the call for that property came from? Are the debug tools using the PHP internal parser to know where the call came from so it can trigger an error if accessing a hidden member?

:'(

Link to comment
Share on other sites

reread my solution and look at the wikipedia page linked by keeB in the first post. the answer is there.

 

Hi! Thanks for the reply.

I went over the abstract Factory solution. But I can't see how this can help.

 

I will try to give examples here, since I don't have the script in here to post.

What I am trying to do is something like this:

 

[pre]class X

{

    public $strSomeString;

    private $arrSomeArray;

    protected $bolSomeBoolean;

 

    public function __construct()

    {

        $this->strSomeString = "Some value";

        $this->arrSomeArray = array("value1", "value2", "etc.");

        $this->bolSomeBoolean = true;

    }

 

    public function __get($var)

    {

      TypeChecker::GetProperty($var);

    }

 

    public function __set($var, $value)

    {

      TypeChecker::SetProperty($var, $value);

    }

}

 

$obj1 = new X();

echo $obj1->SomeString;

var_dump($obj1->SomeArray);

echo $obj1->SomeBoolean;

[/pre]

 

So all the calls above would be to the "name" of the property, NOT its prefix+name. Then the get and set methods would call the TypeChecker class, which would in turn check for the existence of that property and chek to see if the correct type was passed (in case of the set method). It then would need to check the visibility of the property t make sure it can be called form where it is being called.

 

That is why I need to know where the calling came (if fro minside the same class, its children or outside it).

 

Maybe your solution can help me with this, but since I am still no familiar with Patterns, I couln't understand how it would apply.

 

As I posted, I thought about the debug_baktrace option and about parsing it to make sure I know where it is being called from. But since, so far the tests I've run can not really trace the called property back to the origin of the call.

 

So if I have a class A and a class B that instantiates class A, if I call $this->SomeNewVar (from inside class A) or $classB->classAInstance->SomeNewVar, the debug_backtrace array shows me the same object as the source of the call. The only way to use it would be to set that each class has its own file, so if I am inside the same file it wouls allow the call. if not, it would chek if the other class is a child of the first one, to see if the property can be called.

The problem with this is really making sure no one using the classes I am developing will instanciate the object inside the same file or in a different, not class file.

 

Well, still searching... :)

 

Thanks!

 

Link to comment
Share on other sites

I really, really don't understand what you're trying to accomplish.

 

I can't think of any time where I'd want an object to care how or from where it's being called from.

 

Can you please explain the overall goal of the exercise? I think you're trying to make this much harder than it really should be.

Link to comment
Share on other sites

when you extend a class, the child has access to all of the public/protected methods and properties

 

class a{

protected $_var = 'hi, i'm from a';

public function test(){}

}

 

class b extends a{

protected $_varb = 'im from b';

public function testB(){}

}

 

$x = new b();

echo $x->_var; //hi, im from a

echo $x->-varb; //im from b

 

now with the factory, it doesnt need to be abstract, you're doing the same thing except you're calling the parent  and beign returned a child

 

class a{

public fucntion __construct($class){

switch($class){

case 'b':

return new b();

break;

case 'c':

return new c();

break;

}

}

 

public function someBaseFunctionAllChildenWouldUse(){}

}

 

class b extends a{

//class b only functions

}

 

class c extends a{

//class c only functions

}

 

$x = new a('b');

//x is returned with all of b's methods/properties as well as a's

 

$y = new a('c');

//$y has all of c's methods/properties and a's

 

its hard becuase we do not know exactly what you're trying to accomplish. but fromw hat you've told us, this seems to be a solution that i would take

Link to comment
Share on other sites

when you extend a class, the child has access to all of the public/protected methods and properties

 

 

its hard becuase we do not know exactly what you're trying to accomplish. but fromw hat you've told us, this seems to be a solution that i would take

 

I am sorry for not being too clear before. Just now I realized that in my first post I failed to post de sources to my idea.

 

I was going through these two websites about a proposal for sort of a TypeChecker class that would enforce strong typing (type safe or type hinting) properties:

http://jan.kneschke.de/2007/2/19/typesafe-objects-in-php

http://www.cstruter.com/replyblog.php?ContentID=44

 

So I tried to come up with another solution where it would be based on this:

 

1. All field declarations would be done with a prefix, which would point to the type of the field (like $strSomeString, $arrSomeArray and so on).

2. Every class I wanted to work with this strong typed approuch would have a __get and a __set methods which would in turn call the TypeChecker class.

3. Since the magic methods are only called for non declared properties, every property I tried to access would have the syntax ignore the prefix (like if I have a field for class A declared as $strSomeString, I would call it as $objA->SomeString).

4. Since those properties were not declared, the magic methods would handle them, calling the TypeChecker class, which would in turn:

  4.1. check for the existence of a Field with the same Syntax (case sensitive would still work in this case), and any prefix and call an "property not declared" exception if it don't.

  4.2. store in a static variable these fields and the values, for future compare.

  4.3. for a set method, check for type of the value being passed and if it matches the prefix of the field we are trying to set. If not, rises an exception.

  4.4. The big problem: Check if the visibility of the field allows me to access it and rise an exception if don't.

  4.5. If all goes ok, returns me the existing field ($strSomeString, for example).

 

 

So the problem is #4.4. This, as I found out, I can only do if I know from where that property is being called. I will post again the first example.

 

class TestX

{

    public $strSomeString;

    private $arrSomeArray;

    protected $bolSomeBoolean;

 

    public function __construct()

    {

        $this->SomeString = "Some value"; // calls a new $SomeString and NOT $strSomeString

        $this->SomeArray = array("value1", "value2", "etc."); // calls a new $SomeArray and NOT $strSomeArray

        $this->SomeBoolean = true; // calls a new $SomeBoolean and NOT $strSomeBoolean

    }

 

    public function __get($var)

    {

      TypeChecker::GetProperty($var); // calls the class I created to "type safe" the property

    }

 

    public function __set($var, $value)

    {

      TypeChecker::SetProperty($var, $value); // calls the class I created to "type safe" the property

    }

}

 

$obj1 = new TestX();

echo $obj1->SomeString;

var_dump($obj1->SomeArray);

echo $obj1->SomeBoolean;

 

 

 

Note in here that all fields use the prefix to hint its type. But the calls to the properties don't. So they trigger the magic methods which in turn check if everything is ok. The problem is that if I don't know whether "SomeString" is being called from inside the class, its children or outside it, I can't have the TypeChecker class make sure the property can be accessed.

 

Humm.. I hope it is clearer now.

Actually this is kind of a hobby for me, but it's helping me learn heaps about OO in PHP and a lot more, as well as deepen my knowledge of it.

 

My goal is that only by using the more or less traditional type hinting prefix to the properties and a snippet for all classes,  forgetting about the prefix when we call'em (a bit like we do already when we are careless about the type) with the magic methods above, as well as an include to the TypeChecker class (all and all, not too much) I can have a bit of a strong typed php framework to work with :)

 

But this is depending on the knowing where something was called from, which got me stuck. :)

 

Thanks for all the help you gave me so far. It's really helping me learn.

Decio

 

Link to comment
Share on other sites

<?php
function TypeChecker($var) {
  if(is_array($var)) return "array";
  if(is_string($var)) return "string";
  if(is_int($var)) return "string"
  if(is_float($var)) return "float";
  // ???????
}

 

Your problem still makes no sense to me :)

Link to comment
Share on other sites

Hi Keeb,

 

May I AM really making this more difficult than it should be :)

 

The problem with your approuch as I see, is that for every property mutator (set) I would have to call the TypeChecker Class or function, and it would also occur with every acessor (get), to check if the property was already declared. I could certainly do that kind fo thorough check for my could but it would be a hardwired solution, which would failed to help if in any place or class I already use, I didn't place that TypeChecker function call like you did for every property

 

What I am trying to do is 1. make use of the magic methods to help me with not needing to specify or create get and set methods for every property, 2. have a class do all the work of checking the type of each property and if it exists or not, as well as if I can have access to it from where I am calling it or not, 3. prevent that this kind of StrongTyped coding that would done from now one changed too much the general practices we may already have (like type hinting the type of the declared property with prefixes - in this case, only the calls to the properties would be left without the prefixes to trigger the type checking), 4. garantee I don't have to change too much in the classes I already have and use, which I would only need to place the magic __get and __set methods with the call to the Type Checker class.

 

Actually I didn't go too far off from the idea of the people in those articles, one with the solution of using arrays in a child class to declare the properties and their type, and the other doing this with doc comments.

 

I just came up with another solution, but the problem still remains and that is that by triggering the magic methods I am considering the propertiesof my class as public and that ruins the idea of encapsulation.

If there is any way of really capture the call to the property class and where it is being called from, we could solve this problem.

 

I hope this made my idea more clear. Please let me know if it didn't help.

And anyway, thanks for all the help so far. Like I say, I may be making this more difficult than it should be, but I couldn't see other way to do this. :)

 

Decio

Link to comment
Share on other sites

i was thinking of the reflection method. i hope you can use this

 

http://us3.php.net/manual/en/language.oop5.reflection.php

 

Hi, sorry for the late reply.

Yes, I was going over it and, in fact, I am using it on the Type Checker class.

But it doesn't provide anything to track at real time the calling of a property (as far as I saw).

 

I am playing right now with the debug_backtrace function since it's the only one so far that has provided anything close to what I need and I'm doing some tests to understand it's behavior on many different situations where I would call a property to see how I can parse it.

 

Unfortunatelly, I couldn't do many tests on this since saturday, but as soon as I find anything usefull I will post here. Thanks for all the help emehrkay and keeB!

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.