I have a class called Resource but with a fully qualified name like com.example/objects/Resource
If I write a file
use com.example/objects/Resource;
/**
* Do something
*
* #param Resource $r
*/
function myfunc( Resource $r ) {
$r->something();
}
$x = new Resource();
myfunc($x);
Then everything works fine. Because of my use statement, the PHP typehinting is able to handle the the fact that I've passed a variable of type com.example/objects/Resource even though myfunc is only comparing against Resource
The problem is that PHPStorm is not able to handle this. I'm unable to use autocomplete and I get a warning on myfunc($x) which says Expected Resource, got Resource and a warning within the function which says Method 'something' not found in the class Resource. Obviously PHPStorm is assuming I'm using the builtin resource class and not my own Resource class.
If I change the PHPDoc and the function definition to use the fully qualified name, then the previous warnings go away but I get a minor warning which says Unnecessary fully qualified name. I suppose one solution would be to use the fully qualified name and disable the minor warning, but I'd rather not have to use fully qualified names everywhere. I know it's my own fault for creating a class which has the same name as a built in type, but I'm wondering if there is anyway to make this work? Apart from renaming my Resource class?
You can either use an alias when importing the class. More information can be found here. Example:
use com.example\objects\Resource as MyResource;
/**
* Do something
*
* #param MyResource $r
*/
function myfunc( MyResource $r ) {
$r->something();
}
$x = new MyResource();
myfunc($x);
You could also specify the whole namespace and class name instead of just the class name. Example:
/**
* Do something
*
* #param com.example\objects\Resource $r
*/
function myfunc( com.example\objects\Resource $r ) {
$r->something();
}
$x = new com.example\objects\Resource();
myfunc($x);
If you're in a namespace and using this approach, make sure to use a leading \ on your full class name specifier (e.g. $x = new \com.example\objects\Resource();).
Related
How can I indicate that a function/method accepts a class as a parameter? Either PHPDoc or type hinting would be sufficient, but neither seems to allow it.
Here's an example of what I'm thinking should work...
/**
* #param $class class A reference to a class that will be used to do something
*/
function doReallyWeirdStuff(class $class){
$class::callStaticMethod();
}
I'm already aware of how to pass the class to this function. How do I indicate that you should do that?
Class names are merely strings, thus you must type hint them as string. You then need to check it's actually a class, at run-time, in your method:
/**
* #param $class string A reference to a class that will be used to do something
*/
function doReallyWeirdStuff(string $class){
if (class_exists($class)) {
$class::callStaticMethod();
} else {
throw \InvalidArgumentException;
}
}
Note that, to enable strict adherence to string values (as would be required for class names), you need to enable strict type hinting:
declare(strict_types=1);
Otherwise, you could conceivably call like so:
doReallyWeirdStuff(M_PI);
which doesn't make much sense.
You can't do it with PHPDoc type hinting, unless you pass an actual object instance.
You can however abuse the PHP Doc type hinting.
string|Class $class
or
Class $class
This will produce very mixed results depending on what you're running. You'll lose some of the ability to run type checking without false negatives/positives.
Back to development after spending some years in a management position, I am dealing with a PHP code, which has some definitions that I cannot understand (looks like I am far beyond of PHP progress on these years). Can someone let me know what campaignDTO and ParamDTO do in this definition?
What will be returned from this method?
/**
* Creates a campaign
* #param campaignDTO $campaign
* #param ParamDTO $param
* #throws \Exception
* #return campaignDTO
*/
public function createCampaign(campaignDTO $campaign, ParamDTO $param)
{
}
Type declarations as per docs:
Type declarations allow functions to require that parameters are of a
certain type at call time. If the given value is of the incorrect
type, then an error is generated: in PHP 5, this will be a recoverable
fatal error, while PHP 7 will throw a TypeError exception.
These are type-hints for run-time validation. It tells the code to expect objects of class type campaignDTO and ParamDTO, or a class that extends from these.
If you pass in an array, or a string, or something that is not a class that is or extends capaignDTO then the code will throw an error.
The function, as it is, returns nothing.
According to the code-comment, it will return an object of type campaignDTO, which looks like the first parameter.
i have a \Zend\ServiceManager\ServiceManager instance in my code and this function is being returned from a function wich is using the get function from it.
like:
$serviceManager->get('webuser')->IntelSenseHere()
$serviceManager->get('email')->IntelSenseHereLOL()
$serviceManager->get('horses')->IntelSenseHereHEEERE()
Now all thouse classes can be returned from this one call... How could i document what the function call is calling?
Because i have intel sense helper from nb 7.4 rc2 and it is pretty clever and reacts to the return document variable, i would like to specify what adapters it can return.
Is there a way to specify the classes it cann return??
like:
/**
*
* #param \Zend\ServiceManager\ServiceManager $serviceManager
* #param array $user
* #return boolean, \Zend\ServiceManager\ServiceManager, horseAdapter...
*/
Is there a correct syntax for that?
Using the ServiceManager::get($service) will return the instance of the service you requested.
So, using one of your examples:
$serviceManager->get('webuser')->doSomething();
Is the same as:
$webUserService = $serviceManager->get('websuer');
$webUserService->doSomething();
You should therefore add the DocBlock annotation #return to the webUser::doSomething() method, not the ServiceManager::get()
The code completion will depend entirely on your IDE, however I believe this will work in Netbeans.
Quick one on NetBeans 7.0 and autocomplete for PHP;
I'm trying to figure out (if possible) how to force __get() implemented in a class to return (refer to) a certain type, the type being the same class in which __get() is implemented, always.
Right now, I have (in View):
/**
* #param string $key
* #return View
*/
public function __get($key){
return $this->getView($key);
}
Accessed like so:
$view->foo-> // should populate with methods from View
^
Now I've been reading about the #property, but I'm not sure if that's correct for what I'm doing. The other thing is (and this would be a nice feature if possible) typically views are nested, so it's not uncommon in my implementation to see this:
$view->foo->bar->baz-> // should populate with methods from View
^
Any idea on how to force this, or am I stuck?
Update:
So #property seems to be heading the correct direction, however there doesn't seem to be support for wildcarding the property names. So to elaborate on my question, does anyone know of any NetBeans plugins, or undocumented (or just plain hard to find) PHPDoc syntax for supporting wildcard #property names?
I'm thinking in one of these directions:
/**
* #property View *
* #property View ...
* #property View $var,...
*/
Of course, none of these variations work, however the last would seem most logical, as they seem to support a similar syntax for variadic function parameter lists.
Netbeans can work that magic for you with the #property like shown in the example below.
As you already have figured out you will have to define each property in the doc block.
Another possible solution for your $x->y->z->view example is listed below.
Copy & paste this into Netbeans and it will show the methods of the Bar class:
<?php
/**
* #property Bar $prop
*/
class foo {
}
class bar {
public function xyz() {
}
public function abc() {
}
}
$x = new foo();
$x->prop->
When you move the cursor here and press ctrl+space you will see:
If you want autocomplete for a longer resulton chain you can also use
/** #var Viewclass $foo */
$foo = $x->y->z->view;
$foo->autoCompleteWorksNow();
anywhere in your code.
Is it possible in php to load a function, say from a external file to include in a class.
I'm trying to create a loader for helper functions so that I could call:
$registry->helper->load('external_helper_function_file');
after that it should be able call the function in file like this:
$registry->helper->function();
Thanks for any help
Setting aside opinions it it's good OOP design. It's possible even with current version of PHP, although not as clean, as it can be with PHP5.3.
class Helper {
/* ... */
function load($file) {
include_once($file);
}
function __call($functionName, $args) {
if(function_exists($functionName))
return call_user_func_array($functionName, $args);
}
}
ok, 1st, i agree that this is bad manners. also, in 5.3, you could use the new closure syntax with the __call magic word to use operators as functions (JS style).
now, if we want to supply a way of doing this you way, i can think of using create_fnuction, mixed with the __call magic.
basically, you use a regex pattern to get convert the functions into compatible strings, and put themin a private member. than you use the __call method to fetch them. i'm working on a small demo.
ok, here is the class. i got the inspiration from a class i saw a few weeks ago that used closures to implement JS-style objects:
/**
* supplies an interface with which you can load external functions into an existing object
*
* the functions supplied to this class will recive the classes referance as a first argument, and as
* a second argument they will recive an array of supplied arguments.
*
* #author arieh glazer <arieh.glazer#gmail.com>
* #license MIT like
*/
class Function_Loader{
/**
* #param array holder of genarated functions
* #access protected
*/
protected $_funcs = array();
/**
* loads functions for an external file into the object
*
* a note- the file must not contain php tags.
*
* #param string $source a file's loaction
*
* #access public
*/
public function load($source){
$ptrn = '/function[\s]+([a-zA-Z0-9_-]*)[\s]*\((.*)\)[\s]*{([\w\s\D]+)}[\s]*/iU';
$source = file_get_contents($source);
preg_match_all($ptrn,$source,$matches);
$names = $matches[1];
$vars = $matches[2];
$funcs = $matches[3];
for ($i=0,$l=count($names);$i<$l;$i++){
$this->_funcs[$names[$i]] = create_function($vars[$i],$funcs[$i]);
}
}
public function __call($name,$args){
if (isset($this->_funcs[$name])) $this->_funcs[$name]($this,$args);
else throw new Exception("No Such Method $name");
}
}
limitations- 1st, the source cannot have any php tags. 2nd, functions will always be public. 3rd- we can only mimic $this. what i did was to pass as a 1st argument $this, and the second is the array of arguments (which is a 4th limition). also, you will not be able to access non-public members and methods from within the class.
an example for a source file:
function a($self,$arr=array()){
//assuming the object has a member called str
echo $self->str;
}
this was a fun exercise for me, but a bad practice all in all
So you want to not just include a file, but include it into an object's scope?
...
I think you're going about this the wrong way. It makes more sense if the registry object has a series of helper members, which have functions of their own. The net result might look something like this:
$registry->aHelper->aFunction();
$registry->aDifferentHelper->aDifferentFunction();
With careful use of {} syntax, you should be able to dynamically add member objects to your god object.
At this point it's worth noting that a god object is almost invariable an anti-pattern. If you need those functions globally, use a bootstrapping include technique and put then in global scope. If you need to pass that data around, then either pass it to functions as required or store it in a database and retrieve it elsewhere.
I know that god object really looks like a good idea, but I promise you it will make things a mess later on.