PhpStorm does not support yaf's init method - phpstorm

In other class, PhpStorm can identify __construct() function, but in yaf controller it can not identify the initialization method init(), resulting in the init() can not trace initialization operation.
class TestController extends Yaf_Controller_Abstract{
private $model;
public function init() {
$this->model = new TestModel();
}
public function test(){
$this->model->testDeclaration();
}
}
class TestModel{
public function testDeclaration(){
}
}
In this example, I want use 'go to declaration' from test function $this->model->testDeclaration(); to testDeclaration() function in TestModel class. But it does not work.
PhpStorm tells me:
Cannot find declaration to go to
How can I use 'go to declaration' correctly here?

In other class, PhpStorm can identify __construct() function, but in yaf controller it can not identify the initialization method init(), resulting in the init() can not trace initialization operation.
PhpStorm has special treatment for __constructor() -- it tracks what type class variable/property will get if it will have any assignment operations within the method body.
For example, in this code it knows that $this->model will be instance of TestModel class -- IDE keeps this info even outside of the __construct() method body.
For other methods, like init() in your case, such info gets discarded outside (so it's local to the method body only).
You can easily resolve this by using simple PHPDoc comment with #var tag where you will provide type hint for model property:
/** #var \TestModel Optional description here */
private $model;
Make a habit of providing type hint for all properties/class variables, even if IDE autodetects its' type -- it helps IDE in long run.
https://phpdoc.org/docs/latest/references/phpdoc/tags/var.html

Related

In PhpStorm, can Ctrl+Click go to class definition in PHP rather than the constructor?

I'm using PhpStorm and something that lately is bothering me a lot is this scenario. Suppose I have this setup:
// File1.php
abstract class AbstractBase {
public function __construct() {
}
}
// File2.php
class MyClass extends AbstractBase {
}
// File3.php
$var = new MyClass();
Now, if I'm reading the line if File3.php and want to go to MyClass definition if File2.php, the easiest way is to hold the Ctrl button and then click the MyClass name. This works very nicely for functions and member variables, and in PHPDoc comments, but in this case PhpStorm chooses to go to the constructor rather than the class definition. And since MyClass doesn't have a constructor of its own, it goes to the AbstractBase constructor in a completely different file.
I understand that in this case it's ambiguous what I want to do. I also know that I can right-click MyClass and then select Go To and then Type Declaration. But is there a way to configure Ctrl-Click that it would go to the class definition rather the constructor?

Can't call component method from Castle Windsor OnCreate

I'm using Castle Windsor, which generally rocks, however I want it to call a method on my component when it is created and seem to have hit a limitation with OnCreate. For exaxmple:
interface IService1
{
void op1();
}
interface IService2
{
void op2();
}
class MyComponent : IService1, IService2
{
public void Init() // not part of either service
{
}
public void op1()
{
}
public void op2()
{
}
}
// I want to call the component's Init() method when it's created, which isn't part of the service contract
container.Register(Component.For<IService1, IService2>().ImplementedBy<MyComponent>().OnCreate(s => s.Init()));
// I could call something from IService1
container.Register(Component.For<IService1, IService2>().ImplementedBy<MyComponent>().OnCreate(s => s.op1()));
// But I can't call anything from any of the other services
container.Register(Component.For<IService1, IService2>().ImplementedBy<MyComponent>().OnCreate(s => s.op2()));
The first registration won't compile, complaining that it "cannot resolve symbol Init" because the instance passed to the delegate is of type IService1. OnCreate seems a bit limited to me, as in the third case when there are multiple services exposed it only allows you to bind to the first one you declare. I'd have to swap IService1 and IService2 around in order to call op2, but that's just moving the problem around.
Why isn't the type passed in the delegate that of the component being registered? Then I'd be free to call whatever method I like. Is there a way around this? Assume I can't put the Init() code in the component's constructor.
Don't be constrained by the strongly typed nature of C#
Yes, the way the API is constructed it's based off of the first service of the component but you can always cast it down to its actual type (or a secondary service)
.OnCreate(s => ((MyComponent)s).Init())
Alternatively, implement Castle.Core.IInitializable or System.ComponentModel.ISupportInitialize (if you don't want your components to reference Windsor) and then you won't need .OnCreate() at all.
For future reference, here's the relevant documentation.

How to fix Error "A conflict exists with definition * in namespace public." using ASC2.0?

In a class hierarchy where:
MngLayers extends Manager_Panel, which extends Manager_Base...
-- In Manager_Base, I've defined an init() method:
public class Manager_Base {
//....
public function init():void {
//Do initialization here...
}
}
-- In Manager_Panel, I do NOT override the init() method.
-- In MngLayers, I override the init() method.
public override function init():void {
super.init();
//Do custom initialization here...
}
When I attempt to compile this, I get this unhelpful compilation error:
Error: A conflict exists with definition init in namespace public.
I'm not sure this matters, but I'm using the ASC2.0 compiler (from the AIR SDK 3.7) with -inline support.
Is there something broken in the compiler that prevents it from doing simple method-overriding compilation like the previous compiler could?
AH! Damn, well it's just the ASC2.0 not being descriptive enough!
My bad, I had a duplicate init() overriden method in the leaf sub-class (MngLayers) all this time. It would of helped if the compiler pointed out that duplicate one instead!
Hope this helps anyone else making the same rookie mistake! :D

How can I create a subclass that takes in different parameters for the same function name?

So I have made this simple interface:
package{
public interface GraphADT{
function addNode(newNode:Node):Boolean;
}
}
I have also created a simple class Graph:
package{
public class Graph implements GraphADT{
protected var nodes:LinkedList;
public function Graph(){
nodes = new LinkedList();
}
public function addNode (newNode:Node):Boolean{
return nodes.add(newNode);
}
}
last but not least I have created another simple class AdjacancyListGraph:
package{
public class AdjacancyListGraph extends Graph{
public function AdjacancyListGraph(){
super();
}
override public function addNode(newNode:AwareNode):Boolean{
return nodes.add(newNode);
}
}
Having this setup here is giving me errors, namely:
1144: Interface method addNode in namespace GraphADT is implemented with an incompatible signature in class AdjacancyListGraph.
Upon closer inspection it was apparent that AS3 doesn't like the different parameter types from the different Graph classes newNode:Node from Graph , and newNode:AwareNode from AdjacancyListGraph
However I don't understand why that would be a problem since AwareNode is a subClass of Node.
Is there any way I can make my code work, while keeping the integrity of the code?
Simple answer:
If you don't really, really need your 'addNode()' function to accept only an AwareNode, you can just change the parameter type to Node. Since AwareNode extends Node, you can pass in an AwareNode without problems. You could check for type correctness within the function body :
subclass... {
override public function addNode (node:Node ) : Boolean {
if (node is AwareNode) return nodes.add(node);
return false;
}
}
Longer answer:
I agree with #32bitkid that your are getting an error, because the parameter type defined for addNode() in your interface differs from the type in your subclass.
However, the main problem at hand is that ActionScript generally does not allow function overloading (having more than one method of the same name, but with different parameters or return values), because each function is treated like a generic class member - the same way a variable is. You might call a function like this:
myClass.addNode (node);
but you might also call it like this:
myClass["addNode"](node);
Each member is stored by name - and you can always use that name to access it. Unfortunately, this means that you are only allowed to use each function name once within a class, regardless of how many parameters of which type it takes - nothing comes without a price: You gain flexibility in one regard, you lose some comfort in another.
Hence, you are only allowed to override methods with the exact same signature - it's a way to make you stick to what you decided upon when you wrote the base class. While you could obviously argue that this is a bad idea, and that it makes more sense to use overloading or allow different signatures in subclasses, there are some advantages to the way that AS handles functions, which will eventually help you solve your problem: You can use a type-checking function, or even pass one on as a parameter!
Consider this:
class... {
protected function check (node:Node) : Boolean {
return node is Node;
}
public function addNode (node:Node) : Boolean {
if (check(node)) return nodes.add(node);
return false;
}
}
In this example, you could override check (node:Node):
subclass... {
override protected function check (node:Node) : Boolean {
return node is AwareNode;
}
}
and achieve the exact same effect you desired, without breaking the interface contract - except, in your example, the compiler would throw an error if you passed in the wrong type, while in this one, the mistake would only be visible at runtime (a false return value).
You can also make this even more dynamic:
class... {
public function addNode (node:Node, check : Function ) : Boolean {
if (check(node)) return nodes.add(node);
return false;
}
}
Note that this addNode function accepts a Function as a parameter, and that we call that function instead of a class method:
var f:Function = function (node:Node) : Boolean {
return node is AwareNode;
}
addNode (node, f);
This would allow you to become very flexible with your implementation - you can even do plausibility checks in the anonymous function, such as verifying the node's content. And you wouldn't even have to extend your class, unless you were going to add other functionality than just type correctness.
Having an interface will also allow you to create implementations that don't inherit from the original base class - you can write a whole different class hierarchy, it only has to implement the interface, and all your previous code will remain valid.
I guess the question is really this: What are you trying to accomplish?
As to why you are getting an error, consider this:
public class AnotherNode extends Node { }
and then:
var alGraph:AdjacancyListGraph = new AdjacancyListGraph();
alGraph.addNode(new AnotherNode());
// Wont work. AnotherNode isn't compatable with the signature
// for addNode(node:AwareNode)
// but what about the contract?
var igraphADT:GraphADT = GraphADT(alGraph);
igraphADT.addNode(new AnotherNode()); // WTF?
According to the interface this should be fine. But your implemenation says otherwise, your implemenation says that it will only accept a AwareNode. There is an obvious mismatch. If you are going to have an interface, a contract that your object should follow, then you might as well follow it. Otherwise, whats the point of the interface in the first place.
I submit that architecture messed up somewhere if you are trying to do this. Even if the language were to support it, I would say that its a "Bad Idea™"
There's an easier way, then suggested above, but less safe:
public class Parent {
public function get foo():Function { return this._foo; }
protected var _foo:Function = function(node:Node):void { ... }}
public class Child extends Parent {
public function Child() {
super();
this._foo = function(node:AnotherNode):void { ... }}}
Of course _foo needs not be declared in place, the syntax used is for shortness and demonstration purposes only.
You will loose the ability of the compiler to check types, but the runtime type matching will still apply.
Yet another way to go about it - don't declare methods in the classes they specialize on, rather make them static, then you will not inherit them automatically:
public class Parent {
public static function foo(parent:Parent, node:Node):Function { ... }}
public class Child extends Parent {
public static function foo(parent:Child, node:Node):Function { ... }}
Note that in second case protected fields are accessible inside the static method, so you can achieve certain encapsulation. Besides, if you have a lot of Parent or Child instances, you will save on individual instance memory footprint (as static methods therefore static there exists only one copy of them, but instance methods would be copied for each instance). The disadvantage is that you won't be able to use interfaces (can be actually an improvement... depends on your personal preferences).

Can I have conditional construction of classes when using IoC.Resolve?

I have a service class which has overloaded constructors. One constructor has 5 parameters and the other has 4.
Before I call,
var service = IoC.Resolve<IService>();
I want to do a test and based on the result of this test, resolve service using a specific constructor. In other words,
bool testPassed = CheckCertainConditions();
if (testPassed)
{
//Resolve service using 5 paramater constructor
}
else
{
//Resolve service using 4 parameter constructor
//If I use 5 parameter constructor under these conditions I will have epic fail.
}
Is there a way I can specify which one I want to use?
In general, you should watch out for ambiguity in constructors when it comes to DI because you are essentially saying to any caller that 'I don't really care if you use one or the other'. This is unlikely to be what you intended.
However, one container-agnostic solution is to wrap the conditional implementation into another class that implements the same interface:
public class ConditionalService : IService
{
private readonly IService service;
public ConditionalService()
{
bool testPassed = CheckCertainConditions();
if (testPassed)
{
// assign this.service using 5 paramater constructor
}
else
{
// assign this.service using 4 parameter constructor
}
}
// assuming that IService has a Foo method:
public IBaz Foo(IBar bar)
{
return this.service.Foo(bar);
}
}
If you can't perform the CheckCertainConditions check in the constructor, you can use lazy evaluation instead.
It would be a good idea to let ConditionalService request all dependencies via Constructor Injection, but I left that out of the example code.
You can register ConditionalService with the DI Container instead of the real implementation.
My underlying problem was that I was trying to resolve my class which had the following signature:
public DatabaseSchemaSynchronisationService(IDatabaseService databaseService, IUserSessionManager userSessionManager)
This was basically useless to me because my usersessionmanager had no active NHibernate.ISession because a connection to my database had not yet been made. What I was trying to do was check if I did have a connection and only then resolve this class which served as a service to run database update scripts.
When changing my whole class to perform the scripts in a different way, all I needed in its constructor's signature was:
public DatabaseSchemaSynchronisationService(ISessionFactory sessionFactory)
This allowed me to open my own session. I did, however have to first check if the connection was ready before attempting to resolve the class, but having IDatabaseSchemaSynchronisationService as a parameter to another class's constructor; this class also gettting resolved somewhere where I could not check the db connection was a bad idea.
Instead in this second class, I took the IDatabaseSchemaSynchronisationService paramater out of the constructor signature and made it a local variable which only gets instantiated (resolved) :
if (connectionIsReady)
Thanks to everyone who answered.