I'm trying to get NetBeans 6.8 code completion to work for this. It doesn't seem to do it by itself, but I'm wondering if there's some phpdoc magic or something that may help, since it seems pretty darn good at using that.
Take the following two classes:
class A {
public $B;
public function __construct() {
$this->B = new D();
}
public function C() {
echo "C";
}
}
class D {
public $E;
public function __construct() {
// Do stuff.
}
public function F() {
echo "F";
}
}
Now, let's say I do $A = new A(); and then start typing $A->B->
Assuming that both classes are defined in the same file, this works perfectly. I get code complete suggestions for the E variable and the F method.
However, if the classes are split up into A.php and D.php respectively, and included into another file (say, index.php), doing the same thing after including both files gives only No Suggestions.
Any ideas? Thanks in advance!
I think netbeans doesn't look at the actual includes you do, but rather at the project's include path. Set that, and it should work. The reason probably has to do with the fact that most people use autoloading anyway, and following that would be a bit too much to ask.
It works for me in most cases, but if you have problems use /* #var $variable ClassName */ before line with $A = new A()
You can use a shortcut for this: type vdoc and press tab.
To extend upon Mchl's anwser:
If both files are in your project, and you use correct doc-blocks, code completion will find what you're looking for. To give an example:
/**
* Class A
*
* #author Yourname <And#Email>
* #package Example
*/
class A {
/**
* #var D
*/
public $B;
/**
* Constructor
*/
public function __construct() {
$this->B = new D();
}
/**
* Function C
*
* #return string
*/
public function C () {
return "C";
}
}
Typing the /** and hitting enter right before a method or variable will trigger the creation of such a block, provided it has been written already...
Related
I have an interesting scenario in that I need a function to be defined in order to make tests for another function. The function I want to test looks something like this:
if (function_exists('foo') && ! function_exists('baz')) {
/**
* Baz function
*
* #param integer $n
* #return integer
*/
function baz($n)
{
return foo() + $n;
}
}
The reason I am checking for the existence of foo is because it may or may not be defined in a developer's project and the function baz relies on foo. Because of this, I only want baz to be defined if it can call foo.
The only problem is that so far it has been impossible to write tests for. I tried creating a bootstrap script in the PHPUnit configuration that would define a fake foo function and then require the Composer autoloader, but my main script still thinks foo is not defined. foo is not a Composer package and can not otherwise be required by my project. Obviously Mockery will not work for this either. My question is if anyone more experienced with PHPUnit has come across this issue and found a solution.
Thanks!
Start with a slight refactor of the code to make it more testable.
function conditionalDefine($baseFunctionName, $defineFunctionName)
{
if(function_exists($baseFunctionName) && ! function_exists($defineFunctionName))
{
eval("function $defineFunctionName(\$n) { return $baseFunctionName() + \$n; }");
}
}
Then just call it like this:
conditionalDefine('foo', 'bar');
Your PHPUnit test class will contain the following tests:
public function testFunctionIsDefined()
{
$baseName = $this->mockBaseFunction(3);
$expectedName = uniqid('testDefinedFunc');
conditionalDefine($baseName, $expectedName);
$this->assertTrue(function_exists($expectedName));
$this->assertEquals(5, $expectedName(2));
}
public function testFunctionIsNotDefinedBecauseItExists()
{
$baseName = $this->mockBaseFunction(3);
$expectedName = $this->mockBaseFunction($value = 'predefined');
conditionalDefine($base, $expectedName);
// these are optional, you can't override a func in PHP
// so all that is necessary is a call to conditionalDefine and if it doesn't
// error, you're in the clear
$this->assertTrue(function_exists($expectedName));
$this->assertEquals($value, $expectedName());
}
public function testFunctionIsNotDefinedBecauseBaseFunctionDoesNotExists()
{
$baseName = uniqid('testBaseFunc');
$expectedName = uniqid('testDefinedFunc');
conditionalDefine($base, $expectedName);
$this->assertFalse(function_exists($expectedName));
}
protected function mockBaseFunction($returnValue)
{
$name = uniqid('testBaseFunc');
eval("function $name() { return '$value'; }");
return $name;
}
That is sufficient for what you're asking. You can however, further refactor this code extracting the function generation into a code generator. That what you can write unit tests against the generator to make sure it creates the kind of function you expect.
This should work!
use MyProject\baz;
class YourTestCase
{
/** #var callable **/
protected $mockFoo;
/** #var callable **/
protected $fakeFoo;
public function setUp()
{
if (function_exists('foo')) {
$this->mockFoo = function($foosParams) {
foo($foosParams);
// Extra Stuff, as needed to make the test function right.
};
}
$this->fakeFoo = function($foosParams) {
// Completely mock out foo.
};
}
public function testBazWithRealFoo()
{
if (!$this->mockFoo) {
$this->markTestIncomplete('This system does not have the "\Foo" function.');
}
$actualResults = baz($n, $this->mockFoo);
$this->assertEquals('...', $actualResults);
}
public function testBazWithMyFoo()
{
$actualResults = baz($n, $this->fakeFoo);
$this->assertEquals('...', $actualResults);
}
}
Then modify your existing code:
if (function_exists('foo') && ! function_exists('baz')) {
/**
* Baz function
*
* #param integer $n
* #return integer
*/
function baz($n)
{
return foo() + $n;
}
}
namespace MyProject
{
function baz($bazParams, callable $foo = '\foo')
{
return $foo() + $bazParams;
}
}
Then instead of calling baz($n), you need to call:
use MyProject\baz;
baz($bazParams);
It's like Dependency Injection for functions, yo ;-)
Is this sufficient?
to-test.php:
<?php
if (function_exists('foo') && ! function_exists('baz')) {
/**
* Baz function
*
* #param integer $n
* #return integer
*/
function baz($n)
{
return foo() + $n;
}
}
BazTest.php:
<?php
class BazTest extends PHPUnit_Framework_TestCase {
public function setUp()
{
function foo()
{
// Appropriate mock goes here
return 1;
}
include __DIR__ . '/to-test.php';
}
public function testBaz()
{
$this->assertEquals(2, baz(1));
$this->assertEquals(3, baz(2));
}
}
Running the test yields:
PHPUnit 5.4.8 by Sebastian Bergmann and contributors.
. 1 / 1 (100%)
Time: 54 ms, Memory: 8.00MB
OK (1 test, 2 assertions)
It seems this is a situation where you need to mock visibility, which is definitely outside the realm of PHPUnit which a library of classes. So you can still use PHPUnit, but might have to step outside of it to achieve your goal.
The only way I can think of to create a mock of a function is right inside the test case, above the object extending \PHPUnit_Framework_TestCase.
function foo() {
return 1;
}
if (function_exists('foo') && ! function_exists('baz')) {
/**
* Baz function
*
* #param integer $n
* #return integer
*/
function baz($n)
{
return foo() + $n;
}
}
class TestBaz extends \PHPUnit_Framework_TestCase
{
public function test_it() {
$this->assertSame(4,baz(3));
}
}
You might have to create two files, one with foo and one without, or four if you want to test foo/not foo and baz/not baz. This is definitely an outside-the-box option, that I wouldn't normally recommend, but in your case, it might be your best bet.
Adding it in the bootstrap file doesn't work - why?
Is it because sometimes the function baz is (A) correctly created by the system and sometimes (B) you need to mock it? Or (C) do you always need to mock it?
Case A: Why is the code creating a vital function sporadically on the fly?
Case B: A function can only be registrered once, and never unregistered or overwritten. Therefore, you either go with the mock or you don't. No mixing is allowed.
Case C: If you always need to mock it, and you add it to the bootstrap file, it will be defined. Regarding what you've tried, either your bootstrap file for phpunit isn't loaded correctly or you misspelled the function's name.
I'm sure you've correctly configured your phpunit bootstrapping, but for good measure, does it look anything like the following:
/tests/phpunit.xml:
<phpunit
bootstrap="phpunit.bootstrap.php"
</phpunit>
/tests/phpunit.bootstrap.php:
<?php
require(__DIR__ . "/../bootstrap.php"); // Application startup logic; this is where the function "baz" gets defined, if it exists
if (function_exists('foo') && ! function_exists('baz')) {
/**
* Baz function
*
* #param integer $n
* #return integer
*/
function baz($n)
{
return foo() + $n;
}
}
Don't create the function baz on the fly in your tests, e.g. in a setUp function.
Test suites in phpunit use the same bootstrapper. Therefore, if you need to test cases where function baz is defined and other cases where it is not defined (and you need to mock it), you need to split up the tests folder, e.g. in two different folders, each with their phpunit.xml and phpunit.bootstrap.php files. E.g. /tests/with-baz and /tests/mock-baz. From these two folders, run the tests separately. Just create symlinks to the phpunit in each subfolder (e.g. from /test/with-baz create ln -s ../../vendor/bin/phpunit if composer is in the root) to ensure you run the same version of phpunit in both scenarios.
The ultimate solution is, of course, to figure out where the baz function is being defined and manually include the culprit script file, if at all possible, to ensure the correct logic is being applied.
Alternative
Use phpunit's #runInSeparateProcess annotation and define the function as needed.
<?php
class SomeTest extends \PHPUnit_Framework_TestCase
{
/**
* #runInSeparateProcess
*/
public function testOne()
{
if (false === function_exists('baz')) {
function baz() {
return 42;
}
}
$this->assertSame(42, baz());
}
public function testTwo()
{
$this->assertFalse(function_exists('baz'));
}
}
Recently I ran into an interesting situation when implementing a PHP application using PhpStorm. The following code snippet illustrates the problem.
interface I{
function foo();
}
trait T{
/**
* #return string
*/
public function getTraitMsg()
{
return "I am a trait";
}
}
class A implements I{
use T;
function foo(){}
}
class C implements I{
use T;
function foo(){}
}
class B {
/**
* #param I $input <===Is there anyway to specify that $input use T?
*/
public function doSomethingCool($input){ //An instance of "A" or "C"
$msg = $input -> getTraitMsg(); //Phpstorm freaks out here
}
}
My question is in the comment. How do I indicate that $input parameter implements I and uses T?
It's a lit bit hackly, but you can use class_uses it returns list of used traits. And add T as a #param type in PHPDoc for autocomplete
class B {
/**
* #param I|T $input <===Is there anyway to specify that $input use T?
*/
public function doSomethingCool($input){ //An instance of "A" or "C"
$uses = class_uses(get_class($input));
if (!empty($uses['T'])) {
echo $input->getTraitMsg(); //Phpstorm freaks out here
}
}
}
AFAIK you cannot type hint a trait usage in such way (#param only accepts scalar types or classes/interfaces + some keywords).
The ideal solution for you would be placing getTraitMsg() declaration into I interface.
If this cannot be done .. then you can specify that only instances of A or C can be passed here (as they utilize that trait):
/**
* #param A|C $input
*/
public function doSomethingCool($input)
{
$msg = $input->getTraitMsg(); // PhpStorm is good now
}
If names of such possible classes are unknown in advance (e.g. it's a library code and final classes could be anything in every new project or even added in current project at any time) .. then I suggest to use safeguards, which you should be using with such code anyway (via method_exists()):
/**
* #param I $input
*/
public function doSomethingCool($input)
{
if (method_exists($input, 'getTraitMsg')) {
$msg = $input->getTraitMsg(); // PhpStorm is good now
}
}
Why use safeguard? Because you may pass instance of another class K that implements I but does not use trait T. In such case code without guard will break.
Just to clarify: you could use #param I|T $input to specify that method expects instance that implements I or uses T .. but it's only works for PhpStorm (not sure about other IDEs) -- AFAIK it's not accepted by actual PHPDocumentor and does not seem to fit the PHPDoc proposed standard.
"//Phpstorm freaks out here" -- no, it's not. It just tries to signal you that your code is not correct.
The contract of method doSomethingCool() doesn't require $input to expose any method named getTraitMsg(). The docblock says it should implement interface I but the docblock is not code, it only helps PhpStorm help you with validations and suggestions.
Because you didn't type-hinted the argument $input, the code:
$b = new B();
$b->doSomethingCool(1);
is valid but it crashes as soon as it tries to execute the line $msg = $input -> getTraitMsg();.
If you want to call getTraitMsg() on $input you have to:
declare the type of $input;
make sure the declared type of $input exposes a method named getTraitMsg().
For the first step, your existing code of class B should read:
class B {
/**
* #param I $input
*/
public function doSomethingCool(I $input) {
$msg = $input -> getTraitMsg();
}
}
Please remark the type I in front of argument $input in the parameters list.
The easiest way to accomplish the next step is to declare method getTraitMsg() into the interface I:
interface I {
function foo();
function getTraitMsg();
}
Now, the code:
$b = new B();
$b->doSomethingCool(1);
throws an exception when it reaches the line $b->doSomethingCool(1); (i.e. before entering the function). It is the PHP's way to tell you the method is not invoked with the correct arguments. You have to pass it an object that implements the interface I, no matter if it is of type A or C. It can be of any other type that implements interface I and nobody cares if it uses trait T to implement it or not.
I have a class which includes a file in a method like below:
In class.php file:
class A {
const CONST1 = 5;
/** #var int $a */
var $a = 5;
public function call()
{
include( 'b.php' );
}
public function do_some_magic()
{
// magic stuff...
}
public static function static_func()
{
// some code...
}
}
file b.php:
<?php
/** #var A $this */
/** #var A self */ // This doesn't work
$this->do_some_magic();
echo '['.$this->a.']';
self::static_func();
echo '['.self::CONST1.']';
I use PhpStorm as IDE and in b.php file if I want to go to definition of do_some_magic() or definition of a variable it will correctly go to corresponding method or variable definition in class.php file, but if I want to go to definition of constant CONST1 or to definition of static method static_func() it says "Cannot find definition to go to", so I think /** #var A self */ is not a valid notation in included file.
My question is: Is there any way in PhpDoc to tell IDE of what type self is in included file?
I searched for an answer, but as it seems at the moment only way to have auto-complete in an included file you will have to make static calls using class name. Of course, this would fail if you include the file in different classes and you want self to mean that specific class where the file was included.
So b.php would look like:
<?php
/** #var A $this */
/** #var A self */ // This doesn't work
$this->do_some_magic();
echo '['.$this->a.']';
A::static_func();
echo '['.A::CONST1.']';
If however you find a better answer please let me know.
Regards,
Andy
I am using Netbeans, and I love it.
However, my scenario is, when I want to use object B in object A, I can not use the autocomplete feature on $this->B->
(Yes, I know, the below code has syntax error, the question is not about syntax).
So, for example:
require_once('Legion.class.php');
class MyClass {
private $Legion;
public function __construct() {
$this->Legion = Legion::getInstance();
}
public function showResult() {
$this->Legion-> //Not works here
$Legion = $this->Legion;
$Legion-> //Works
}
}
When I typed $this->Legion-> I've got some basic functions, keywords, like do, echo, while etc...
But if I am create a new variable for this object B, then I've get back all of it accessable methods, and properties.
After this I've also tried to use vdoc without success:
/* #var $Legion Legion */
/* #var $this->Legion Legion */
Is somebody faced with this issue? Is there a solution for that?
Try to use correct PHP Doc
/**
* My Legion
* #var Legion
*/
private $Legion;
-> http://manual.phpdoc.org/HTMLSmartyConverter/PHP/phpDocumentor/tutorial_tags.var.pkg.html
I want to write something like (laravel uses):
View::make('FooBarView')->with('foo', $foo)
->with('bar', $bar);
My knowledge and imagination made me to use new self instances. But I don't think that this is the best idea around and I could not handle it.
Google couldn't help me because of my bad keywords I think. I don't want to make you write code for me for sure but what is the name of this design pattern or whatever?
In laravel's source, with function uses
return $this;
But how to use it after make?
By the way, in this example; with method helps you to set variables for view's render.
To call what the function returns, the function will have to return something that is possible to call.
In this case, you could for example return "this":
class View {
/**
* #returns View
*/
public static function make($foo) {
/* do stuff, return new View instance */
return new View();
}
/**
* #returns View
*/
public function with($foo, $bar){
/* do stuff */
return $this;
}
}
That way, whenever you call with you will get the class instance back, which in turn will be callable:
View::make("foo")->with("foo")->with("bar");
// Will be same as:
$v = View::make("foo");
$v = $v->with("foo");
$v = $v->with("bar");