Methods not found in autoloaded classes

Answered

So I have a bunch of older PHP projects.     

There is an /includes directory at the save level as the document root.  There is an _includes directory inside each of the projects.

Each top-level file includes _includes/site_config.php which contains a call the spl_autoload_register for an autoloader function.

Under External Libraries, I added /var/www/html/includes, which has subdirectories containing classes. 

Lots of clases are instantiated in _includes/site_config:

 $WLCAccountClass = new Controller\WLCUser( );

then are used in the file that included _includes/site_config, such as:

if( $WLCAccountClass->GetLoggedIn() &&
$WLCAccountClass->GetAccountLevel() != AGENCYADMIN &&
$WLCAccountClass->GetAccountLevel() != AGENCYUSER )

The method names under $WLCAccountClass are all highlighted as "method not found".  

Note that Controller is a directory under /var/www/html/includes, which was added to the external libraries. 

How can I get these methods to be found by PhpStorm.

Thanks, 

Ed Greenberg

7 comments

I should point out that the call to $e->getMessage() is also highlighted as not found:

...
} catch (Exception $e) {
file_put_contents('/var/www/log/cache.log', sprintf("%s %s %s\n\n", date("Y-m-d H:m:s"), "Caught Exception from GoogleTranslateWithMemcached: ", $e->getMessage()), FILE_APPEND);
$caught = true;
}


Phpstorm can't even find "Exception?"

0

Hi there,

It's a bit hard to "debug" your situation as it's hard to see the whole picture from description alone.

The general advice, especially if it was working before and suddenly stopped: please try "File | Invalidate Caches .. " and restart IDE.

2nd: RE: Exception -- maybe you have somehow disabled the appropriate stub file? Check "PHP Runtime" tab on "Settings/Preferences | Languages & Frameworks | PHP"

Other than that -- need to know a bit more info about where $WLCAccountClass is instantiated and where it is actually used. if in different files -- maybe you need to typehint it with PHPDoc @var comment ...

1

Hi, Andriy, Thank you for taking a look at the problem with me. 

First, this has ALWAYS been a problem. It didn't just stop working. 

$WLCAccountClass is instantiated in ./_includes/site_config.php, and is used in many files both in . and in other subdirectories of . (where . is the document root.)  Site_config is always included using a relative path, not via a php_include_path.

It's methods are always highlighted as not found. 

It's not the only class whose methods are not found, it's just representative. 

I've tried the two suggestions you made, with no luck.

Thanks, 

Ed

0

OK .. so you are working with manual include/require management. Old style ... kind of like WordPress does.

If so -- try marking such declarations with @global tag like WP does.

Otherwise -- please make some simple test project (reduce your to just 3-4 or so simple files) that I can play with.

 

In modern frameworks where you have Dependency Injection + Location Containers etc ... you do not need to use plain global variables at all. PhpStorm does not really track such "variable defined here in one place and then somehow get used in include file there" usages. There is an option to inspection .. but I do not think it does much. So proper documenting with PHPDoc comments does help.

There are other ways (IoC containers / Registry class / some static helper methods / passing dependent variables into function/class instead of relaying on global state) that are also more IDE friendly ... but that requires more code change than adding @global or alike PHPDoc.

 

P.S. "if in different files -- maybe you need to typehint it with PHPDoc @var comment ..." -- when I've said that I meant that it needs to be documented this way where it is used.

0

Andriy,

This is happening to me in a modern-day (Laravel) project as well. 

If we can resolve it there, it may lead to me resolving it in the legacy stuff. 

For instance, in the code below,  Crypt is highlighted as not defined.  Crypt is a Laravel Facade.  See https://laravel.com/api/5.5/Illuminate/Support/Facades/Crypt.html

<?php

namespace App\Traits;

use Crypt; // crypt is a Laravel Facade.
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Encryption\EncryptException;

use Carbon\Carbon;

trait Encryptable
{
// snip

public function getAttribute($key)
{
if ( is_array( $this->encrypted_date_fields ) && in_array( $key, $this->encrypted_date_fields ) && !empty( $this->attributes[$key] ) )
{
return Crypt::decrypt($this->attributes[$key]);
}
else if (in_array($key, $this->encrypted_fields) && !empty( $this->attributes[$key] ) )
{
return Crypt::decrypt($this->attributes[$key]);
}

return parent::getAttribute($key);
}
// snip


The problem also exists whenever I use a Laravel model:

<?php

namespace App\Http\Controllers\Api\AssistanceCheck;


use App\Model\AssistanceCheck\Account;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Validator;

use App\Http\Resources\Api\v1\AccountResource;
use App\Http\Resources\Api\v1\AccountsResourceCollection;

use App\Model\AssistanceCheck\User;
use App\Model\AssistanceCheck\AccountUser;

use Carbon\Carbon;

class AccountController extends Controller
{

/**
* @param AccountRequest $request
* @return AccountResource
*/
public function createtestaccounts( $number, Request $request)
{
$agency = $request->user( );

if($agency->TestCustomer != 1) abort(403, 'Available for test customers only');

$accounts = Account::createTestAccounts($agency->AgencyID, $number);

return AccountResource::collection($accounts);
}

/**
* @param $key
* @param Request $request
* @return AccountResource
*/
public function retrieve( $key, AccountRequest $request )
{
$agency = $request->user( );

$account = Account::where( 'AccountID', $key )
->where('AgencyID', $agency->AgencyID)
->first( );

$resource = new AccountResource($account);
return $resource;

}
// snip

 

Note that I use App\Model\AssistanceCheck\Accounts.  In the createtestaccounts method, I call the static method Accounts::createTestAccounts() and Phpstorm does not highlight the class or the method, and I can ^B on the method name and go to it.

In the retrieve method, $account is not highlighted, nor is Account::, and I can get to the Account class with ^B.  

class Account extends Model, which is specified. In the Account.php file, I 'use' it with it's full namespace specifier.  Back in the fragment above, the where method, which Account inherits from Model, is highlighted as not-found and generates a PHP warning in Phpstorm.  This fills my code with warnings. 

Anyway, that's a more modern example of the trouble I'm having with this, and I'd really like to understand how PhpStorm finds these things. 

Once again, I thank you for your attention.

Ed G

0

For Laravel: https://github.com/barryvdh/laravel-ide-helper + Laravel Plugin

I'm using Laravel for a bit more than 1 year now -- the above tools resolve almost everything.

 

Laravel uses tons (a lot) of magic (facedes and converting calls to non-existing static methods into instance ones) ... while not always having it documented to full extent (e.g. "@return mixed" -- can be anything). In such circumstances PhpStorm cannot resolve it on its own (especially since it does not know how Laravel functions under the hood as it does not provide any special support just for Laravel)... and here is where the aforementioned tools help.

Also: https://confluence.jetbrains.com/display/PhpStorm/Laravel+Development+using+PhpStorm

 

>For instance, in the code below,  Crypt is highlighted as not defined.  Crypt is a Laravel Facade.  See https://laravel.com/api/5.5/Illuminate/Support/Facades/Crypt.html

There is no class with FQN "\Crypt" -- it's handled dynamically at runtime by Laravel core by redirecting all into facede class. IDE helper will generate special file with such class defined + other stuff.

 

>class Account extends Model, which is specified. In the Account.php file, I 'use' it with it's full namespace specifier.  Back in the fragment above, the where method, which Account inherits from Model, is highlighted as not-found and generates a PHP warning in Phpstorm.  This fills my code with warnings. 

Thing is: \Illuminate\Database\Eloquent\Model class does not have "where()" method -- it comes from \Illuminate\Database\Eloquent\Builder . Laravel magic in action -- it makes it work as if it available in Model class itself.

That's why I always add these 2 lines in PHPDoc for every class that extends Model -- helps with non-static calls at very least (I'm trying to avoid magic calls conversion as much as possible).

 * @mixin \Illuminate\Database\Eloquent\Builder
 * @mixin \Illuminate\Database\Query\Builder

P.S. Aforementioned IDE Helper adds such lines to the Laravel's Model class (modifies Laravel code) .. and it somehow makes it even worse for me (at least for the way how I use it: using model instance ("$this->account->newQuery()->where()") instead of static calls ("Account::where()"). That's why I'm adding it into my models myself + keep Laravel's Model class intact.

1

Andriy, I'm still working with this, and I want to thnk you for your help. I will be back if further questions are discovered.  (Note, I'm off to Laracon next week, so will not be doing much with this until August. )

Thanks, 

Ed

0

Please sign in to leave a comment.