NuSphere Forums Forum Index
NuSphere Forums
Reply to topic
Code Insight challenge for PHP5.3
Guru master

Joined: 05 Jul 2004
Posts: 659
Location: Belgium
Reply with quote
I have a base class with an object factory in the form of a static Create() function.
All instances of derived classes are created using that function.

This function uses get_called_class to determine from which class the call originated and then creates "one of those".
Naturally the editor complains about not being able to identify the value returned by the get_called_class function.

Here comes the question: Is there a way (will there be any way) to "simply" specify that the return type of a function is the class that called it?
View user's profileFind all posts by BlizzSend private messageVisit poster's website


Joined: 21 Mar 2008
Posts: 8
Reply with quote
This looks like a similar problem to mine... ( how-to-use-type-hints-for-fluent-interfaces-t6315.html ) How to specify that given method returns $this (the derived class type) at the end?
View user's profileFind all posts by aargothSend private message
Site Admin

Joined: 13 Jul 2003
Posts: 8334
Reply with quote
Well. To make it clearer, please tell me what class instance is returned in the following example:

Code:

class AAA {
  function BBB() {
    return $this;
  }
}


same goes to get_called_class():

Code:

class AAA {
  function BBB() {
    return get_called_class();
  }
}


I hope it's perfectly clear that AAA is not the only variant. If you can't tell all the variants, why do you expect the IDE to know them?

_________________
The PHP IDE team
View user's profileFind all posts by dmitriSend private messageVisit poster's website
Guru master

Joined: 05 Jul 2004
Posts: 659
Location: Belgium
Reply with quote
Isn't there a possibility to specify a keyword as the return type (#caller or so perhaps, no idea) to let PHPEd know that the type of object it can expect from that function is the same as the class calling it? Just thinking out loud here. I know that would be a break with phpDoc compatibility but won't this become a bigger problem now that there is a get_called_class function?

For $this it is a lot harder, but the parser in the IDE knows which class does the function call normally right?
View user's profileFind all posts by BlizzSend private messageVisit poster's website


Joined: 09 Jul 2009
Posts: 13
Reply with quote
The parser in the IDE, if it's keeping a reference of all the calls in the IDE (a lot of memory) would know which classes could call the function, but there could be many of those. At which point the parser wouldn't be able to know which one.

I think the best solution for this would be for the parser to recognize Vardoc comments for type hinting inside the functions. Much like Zend Studio does. This way you could be using a factory and force the IDE to recognize it as a given class. Something like
Code:
/**
 * @var CarObject
 */
$car = Factory::create('car');


Then the IDE could recognize that $car is an instace of CarObject, etc.

Basically the same way it determines the type of function arguments, just in-code
View user's profileFind all posts by killermonkSend private message
Guru master

Joined: 05 Jul 2004
Posts: 659
Location: Belgium
Reply with quote
I imagine the IDE parsing the file when you open it and, for each variable assigned after a function call, attempting to fetch the type from the lower level (called functions). In that case a stack trace is available and it is pretty easy to determine the calling class type. This naturally is a really simplified explanation and does not account for globals, caching and so on.
I've written a parser or 2 in my life already and technically it is (should be) possible IMHO. Everything depends on how things are handled.

The reason for me asking the question is exactly to avoid having to type each and every variable generated through one of the factory functions.
View user's profileFind all posts by BlizzSend private messageVisit poster's website


Joined: 09 Jul 2009
Posts: 13
Reply with quote
I can see it working that way IFF the parser is actually "executing" the PHP file (and the functions it calls). In some instances this would be efficient and able to quickly get a code insight from something like a factory.

In other cases, it would have to go down three level through business logic and other such obfuscation only to run into something that connects to the database for information where it will fail.

It can be done, but, in some cases, it would just not be a very efficient or effective way of implementing code insights.
View user's profileFind all posts by killermonkSend private message


Joined: 21 Mar 2008
Posts: 8
Reply with quote
As I see it, the simple solution is:

Code:
/**
 * Method description...
 *
 * @return this Instance of this class.
 */

public function test() {
  return $this;
}
View user's profileFind all posts by aargothSend private message
Site Admin

Joined: 13 Jul 2003
Posts: 8334
Reply with quote
Quote:
For $this it is a lot harder, but the parser in the IDE knows which class does the function call normally right?


No. It does not.
$this can be an instance of the method's class or any of the successors:

Code:
class AAA {
   function BBB() {
      return $this;
   }
}

class CCC extends AAA {   
}

$c = new CCC();
var_dump($c->BBB());

$a = new AAA();
var_dump($a->BBB());

_________________
The PHP IDE team
View user's profileFind all posts by dmitriSend private messageVisit poster's website
Guru master

Joined: 05 Jul 2004
Posts: 659
Location: Belgium
Reply with quote
Yes Dmitri but my original question has nothing to do with "$this", that was "added" by aargoth to point out similarities with his one.

My question is as follows:
Code:

class Base
{
   /**
   * @return <SomeKeywordToIndicateTheCallingClass> eg #caller
   */
   function Create ( )
   {
      $sClass = get_called_class  ( );
      return new $sClass ( );
   }
}

class Item extends Base
{
}

$oItem = Item::Create ();


So basically the code insight knows this is an instance of "Item" without me having to add /** @var Item */ before every call.
View user's profileFind all posts by BlizzSend private messageVisit poster's website
Veteran

Joined: 30 Aug 2006
Posts: 116
Reply with quote
I'm now encountering this exact problem while coding a base Model class which offers simple CRUD operations. I'm using 5.3 Late Static bindings and get_called_class( ); in order to make the base class more intelligent about allowing child classes to replace any function in the base class but I lose Code Insight as a result.

Code:

class SimpleModelClass {

   /**
    * create an object and load it with values from array
    * @param str   $array   an array, such as $_POST
    * @public
    * @return SimpleModelClass
    */
   public static function load_from_array(array $array) {
      $class = get_called_class();
      $object = new $class();
      $object->import($array,$values);
      return $object;
   }

}

class UserModel extends SimpleModelClass {
   public function bark() {
      echo "woof!";
   }
}

$user = UserModel::load_from_array($_POST);
$user->bark();


In the above example Code Insight will have no knowledge that the $user object is an instance of UserModel. I added the type hinting in the base class so that at least the base methods and properties are available. I would love the "#caller" method that Blizz is suggesting.

Barring that we'd be forced to do one of the following (both of the below work, but are not ideal, especially the second example which means you add functions for no reason except to help type hint for Code Insight)

Code:

/**
 * user object
 * @var UserModel
 */
$user = UserModel::load_from_array($_POST);
$user->bark();


or :

Code:

class UserModel extends SimpleModelClass {
    /**
    * create an object and load it with values from array
    * @param str   $array   an array, such as $_POST
    * @public
    * @return UserModel
    */
   public static function load_from_array(array $array, $values=null, Db $db=null) {
      return parent::load_from_array($array);
   }   

   public function bark() {
      echo "woof!";
   }
}
View user's profileFind all posts by rudderSend private message
Guru master

Joined: 05 Jul 2004
Posts: 659
Location: Belgium
Reply with quote
Unfortunately theres no other way at this moment. I am constantly fighting s*t like this because of the framework I use. Often even the @var approach doesn't work.

Small pointer btw: /** @var UserModel */ also works, which is far less intrusive than the docblock you used. Smile
View user's profileFind all posts by BlizzSend private messageVisit poster's website
Code Insight challenge for PHP5.3
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
All times are GMT - 5 Hours  
Page 1 of 2  

  
  
 Reply to topic