<p>Your service’s <code>init()</code> function gets called immediately after it is loaded – and before Yii has had a chance to remember that <code>craft()-&gt;myPlugin</code> should return the service instance.</p>

<p>Take a look at <a href="https://github.com/yiisoft/yii/blob/master/framework/base/CModule.php#L393-L394" rel="nofollow">these two lines</a> from CModule::getComponent() (the method that the magic getter invokes when you call <code>craft()-&gt;somePluginName</code>):</p>

<pre><code>$component-&gt;init();
return $this-&gt;_components[$id]=$component;
</code></pre>

<p>So when <code>MyPlugin_OtherService::methodInOtherService()</code> tries to refer back to <code>craft()-&gt;myPlugin</code>, <code>craft()-&gt;myPlugin</code> has not yet been assigned to the service instance, which results in the PHP fatal error you’re getting.</p>

<p>I can propose a change that would fix this:</p>

<pre><code>$this-&gt;_components[$id] = $component;
$component-&gt;init();
return $component;
</code></pre>

<p>…but I’m not sure what the implications would be for that.</p>

<p>You might just need to question whether it’s so important for this code to be running from <code>init()</code> as opposed to another function that you’d have to invoke manually. Having it in <code>init()</code> could lead to other unexpected consequences as well.</p>

CC BY-SA 3.0
2014-07-08T22:51:23.097Z
To be clear, I'm talking about two services within the same plugin.
Lindsey D
CC BY-SA 3.0
2014-07-08T23:07:57.723Z
@LindseyD Sorry, totally missed that. Updated my answer.
Brandon Kelly
CC BY-SA 3.0
2014-07-08T23:10:17.660Z
+1 for moving it out of init() and explicitly calling it.
Brad Bell
CC BY-SA 3.0
2014-07-08T23:35:05.587Z
Thanks Brandon. I've got it in the `init` because it's a pretty big piece of the puzzle, and many other facets of the plugin depend on the data generated there. But, if I'm understanding you correctly, you are suggesting that I remove that method call from the init, and instead simply call it manually before any possible scenario where the data might be needed? Then I would probably have to set an `alreadyRun` property in my main service class so I can easily determine if the process has been run. Does that sound like a better solution to you?
Lindsey D
CC BY-SA 3.0
2014-07-08T23:51:03.283Z
Any reason you don’t put the code in your main plugin class’s `init()` function? That’s probably safer.
Brandon Kelly
CC BY-SA 3.0
2014-07-08T23:59:52.330Z
Ah, so I can just move it to the `init` of `MyPlugin.php`? Would all of the necessary Service files have been loaded by that point?
Lindsey D
CC BY-SA 3.0
2014-07-09T00:03:09.100Z
@LindseyD yep, it will get called at the beginning of each request, and all your services will be available at that point.
Brandon Kelly
CC BY-SA 3.0
2014-07-09T00:16:36.450Z
Awesome, then that's my new plan! Thanks Brandon!
Lindsey D
CC BY-SA 3.0
2014-07-08T22:50:13.343Z
2014-07-08T23:07:42.833Z
2014-07-08T23:07:42.833Z
Brandon Kelly
<p>I have two Services in my plugin. <code>MyPluginService</code> is the "main" service, and <code>MyPlugin_OtherService</code> accomplishes some other tasks (when it is occasionally needed).</p>

<p>There is an <code>init</code> method in <code>MyPluginService</code> which starts a chain of events, and under certain circumstances will call a method in <code>MyPlugin_OtherService</code>.</p>

<h3>MyPluginService</h3>

<pre><code>public function init() {
    parent::init();
    if ("conditions are met") {
        craft()-&gt;myPlugin_otherService-&gt;methodInOtherService();
    }
}

public function methodInMainService() {
    // ...
}
</code></pre>

<h3>MyPlugin_OtherService</h3>

<pre><code>public function methodInOtherService() {
    craft()-&gt;myPlugin-&gt;methodInMainService();
}
</code></pre>

<p>While the method in <code>MyPlugin_OtherService</code> is being run, it will refer <em>back</em> to a method in <code>MyPluginService</code>. This is where the error is triggered:</p>

<blockquote>
  <p>Fatal error: Call to undefined method stdClass::methodInMainService()</p>
</blockquote>

<p>I don't understand why it's not recognizing that call to the main service method. Hasn't the main service already been initialized before this point? There is a lot about "lazy loading" that I don't understand, maybe this falls in that knowledge gap.</p>

<plugin-development><services>
Error when calling methods between two services (triggered by init)
# Error when calling methods between two services (triggered by init)

(Asked by: username_0 on 2014-07-08)

I have two Services in my plugin. MyPluginService is the "main" service, and MyPlugin_OtherService accomplishes some other tasks (when it is occasionally needed).
There is an init method in MyPluginService which starts a chain of events, and under certain circumstances will call a method in MyPlugin_OtherService.
MyPluginService
public function init() {
    parent::init();
    if ("conditions are met") {
        craft()->myPlugin_otherService->methodInOtherService();
    }
}

public function methodInMainService() {
    // ...
}

MyPlugin_OtherService
public function methodInOtherService() {
    craft()->myPlugin->methodInMainService();
}

While the method in MyPlugin_OtherService is being run, it will refer back to a method in MyPluginService. This is where the error is triggered:

Fatal error: Call to undefined method stdClass::methodInMainService()

I don't understand why it's not recognizing that call to the main service method. Hasn't the main service already been initialized before this point? There is a lot about "lazy loading" that I don't understand, maybe this falls in that knowledge gap.

**Tags:** plugin-development, services

---

## 1 answers

### Answer by username_1 on 2014-07-08. Score: 2 | Accepted answer

Your service’s init() function gets called immediately after it is loaded – and before Yii has had a chance to remember that craft()->myPlugin should return the service instance.
Take a look at these two lines from CModule::getComponent() (the method that the magic getter invokes when you call craft()->somePluginName):
$component->init();
return $this->_components[$id]=$component;

So when MyPlugin_OtherService::methodInOtherService() tries to refer back to craft()->myPlugin, craft()->myPlugin has not yet been assigned to the service instance, which results in the PHP fatal error you’re getting.
I can propose a change that would fix this:
$this->_components[$id] = $component;
$component->init();
return $component;

…but I’m not sure what the implications would be for that.
You might just need to question whether it’s so important for this code to be running from init() as opposed to another function that you’d have to invoke manually. Having it in init() could lead to other unexpected consequences as well.

> **Comments:**
> **username_0**: To be clear, I'm talking about two services within the same plugin.  
> **username_1**: @LindseyD Sorry, totally missed that. Updated my answer.  
> **username_2**: +1 for moving it out of init() and explicitly calling it.  
> **username_0**: Thanks Brandon. I've got it in the `init` because it's a pretty big piece of the puzzle, and many other facets of the plugin depend on the data generated there. But, if I'm understanding you correctly, you are suggesting that I remove that method call from the init, and instead simply call it manually before any possible scenario where the data might be needed? Then I would probably have to set an `alreadyRun` property in my main service class so I can easily determine if the process has been run. Does that sound like a better solution to you?  
> **username_1**: Any reason you don’t put the code in your main plugin class’s `init()` function? That’s probably safer.  
> **username_0**: Ah, so I can just move it to the `init` of `MyPlugin.php`? Would all of the necessary Service files have been loaded by that point?  
> **username_1**: @LindseyD yep, it will get called at the beginning of each request, and all your services will be available at that point.  
> **username_0**: Awesome, then that's my new plan! Thanks Brandon!  

---

