I want to fetch a method's comments,take below method for example:
/**
* Returns the regex to extract all inputs from a file.
* #param string The class name to search for.
* #return string The regex.
*/
public function method($param)
{
//...
}
the result should be
Returns the regex to extract all inputs from a file.
#param string The class name to search for.
#return string The regex.
the way I find is use a function like file_get_content to get file content -> filter the method I want -> fetch the comment use regexp
it seems a bit complicated , is there any convenient way to archive this?
actually you can get a method's doc comments with getDocComment
$ref=new ReflectionMethod('className', 'methodName');
echo $ref->getDocComment();
If you want to use the comment in PHP for something check out getDocComment in php's reflection api
PHP Doc. Like Java Doc.
For a method dump I use this little function I composed.
It fetches all methods from provided class that are public(and thus of use to you).
I personally use a dump() method to nicely format the outputted array of method names and descriptions, but that's not needed if you wish to use it for something else :-)
function getDocumentation($inspectclass) {
/** Get a list of all methods */
$methods = get_class_methods($inspectclass);
/** Get the class name */
$class =get_class($inspectclass);
$arr = [];
foreach($methods as $method) {
$ref=new ReflectionMethod( $class, $method);
/** No use getting private methods */
if($ref->isPublic()) {
$arr[$method] = $ref->getDocComment();
}
}
/** dump is a formatting function I use, feel free to use your own */
return dump($arr);
}
echo getDocumentation($this);
Related
What can I use other than if(!empty( $product->a_funky_function() )) to check if the method is empty before calling it?
I've tried method_exists() and function_exists() and a whole plethora of conditions. I think the issue is that I need to have my $product variable there.
Please help.
A fairly common pattern is to have two methods on your class, along the lines of getField and hasField. The former returns the value, and the latter returns true or false depending whether or not the value is set (where "set" can mean not null, or not empty, or whatever else you might want it to mean).
An example:
class Foo
{
/** #var string */
private $field;
/**
* #return string
*/
public function getField()
{
return $this->field;
}
/**
* #return bool
*/
public function hasField()
{
return $this->getField() !== null;
}
}
This would then be used like:
if ($foo->hasField()) {
$field = $foo->getField();
...
}
Often, like in this example, the has... method often just delegates to the get... method internally, to save duplicating the logic. If the getter contains particularly heavy processing (e.g. a database lookup or API call), you might want to factor in ways to avoid performing it twice, but that's a bit out of scope.
You need absolutely to call it so it can compute the value which it will return, so I think there is no other way to know if it will return something not empty without calling it...
You have to call it.
$result = $product->getFunction();
if(!empty($result)) {
//your code here
}
I can not figure out how to deserialize a object from a array of IDs? Here is a simple example my array.
"roles":["1","2","3"]
But when trying I get the error that object expected-class AppBundle\Entity\Role... is There something for this? Thank you all for your attention!
The problem is the one mentioned by LBA in his answer. Basically in order for jms serializer to create an object, it need to be provided with an Array. The solution if you are ok with changing the structure of the api is also good.
I'm assuming your $role jms configuration looks something like this
/**
* #var ArrayCollection
*
* #JMS\Expose
* #JMS\Accessor(setter="setRoles")
* #JMS\SerializedName("roles")
* #JMS\Type("ArrayCollection<Role>")
* #JMS\Groups({"...."})
*
*/
private $roles;
In this case Jms will expect to get and array of arrays just like LBA mentioned. If instead you want he keep the current structure ("roles":["1","2","3"]) instead of "roles":["id": 1], ["id": 2], ["id": 3]], there is an alternative. You can extend the JsonDeserializationVisitor and this a very powerful tool in your arsenal to do almost anything you like with jms.
To do this first change your #Type like this(you will understand why latter)
* #JMS\Type("ArrayCollection<Role,Expand<id>>")
Now you use parameter overwrite, to extend JsonDeserializationVisitor, like this
<parameter key="jms_serializer.json_deserialization_visitor.class">MyBundle\Services\JsonDeserializationVisitor.php</parameter>
And then go and define the new Visitor something like this.
<?php
namespace MyBundle\Services\JmsSerializer;
use JMS\Serializer\Context;
use JMS\Serializer\JsonDeserializationVisitor as ParentJsonDeserializationVisitor;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
class JsonDeserializationVisitor extends ParentJsonDeserializationVisitor
{
/**
* #param PropertyMetadata $metadata
* #param mixed $data
* #param Context $context
*/
public function visitProperty(PropertyMetadata $metadata, $data, Context $context)
{
//This type is the information you put into the #Type annotation.
$type = $metadata->type;
$expand = null;
.......
/*Here you can extract the Expand<id> part that you added to the #Type config.
The Expand part will help you identify the fact that this property needs to be expanded and the id part will tell you how to expand id.
Based on if you do find this you will probably set a variable like $expand = $key, where $key is the "id" part.*/
......
if ($expand !== null) {
$expandedData = [];
foreach($data as $key->$value)
{
$expandedData[$key]=["$expand":$value];
}
parent::visitProperty($metadata, $expandedData, $context);
} else {
parent::visitProperty($metadata, $data, $context);
}
}
This is the basic stuff. Feel free to refactor the code however you like, this is just for fast proof of concept. Also Expand is just how i named this into the exemple. You can use it with whatever name you like. Sorry for not providing the code to extract this from $type but i don't remember the structure of $type right now. Also the structure will change if you do something like Expand<'id'> so play with it and see which fits best for you. Basically with this method you can extend and add features to any jms type you want. For instance you can add something like
#JMS\Type("string<translatable>")
And then extend JsonSerializationVisitor:visitString to call $translator->trans($data) on $data before returning it, and so you can translate a string before serializing it.
Something like this
<?php
namespace MyBundle\Service\JmsSerializer;
use JMS\Serializer\Context;
use JMS\Serializer\JsonSerializationVisitor as ParentJsonSerializationVisitor;
use Symfony\Component\Translation\Translator;
class JsonSerializationVisitor extends ParentJsonSerializationVisitor
{
/**
* #var Translator;
*/
private $translator;
const TRANSLATABLE = "translatable";
/**
* #param string $data
* #param array $type
* #param Context $context
* #return string
*/
public function visitString($data, array $type, Context $context)
{
$translatable = $this->getParameters(self::TRANSLATABLE, $type['params']);
if ($translatable) {
$data = (string)$this->translator->trans($data);
}
return parent::visitString($data, $type, $context);
}
.....................
Hope this helps. Let me know if you have any questions.
Alexandru Cosoi
It is deserializing your array, but it tries to deserialize it into an array of objects of type AppBundle\Entity\Role which seems not to be compatible with your values "1", "2" and so on and therefore throws an error as it cannot instansiate the objects.
You'll have to make sure that your content fits to the expected class.
If you can share your Class Definition for Role we might be able to help you how your array should look like (e.g. something like [["id": 1], ["id": 2], ["id": 3]] probably).
How i can create a PHPDoc block for an declarative array?.
For example, let's say that i have the next function:
/**
* #return ??????????
*/
function dummy() {
$x1=array("key1"=>"hello","ke2"=>"world");
return $x1;
}
// ... later
$x1=dummy();
echo $x1["key1"];
I want to be explicit in the array result, instead of use #return array.
(i also tried) I also know that i can return an array of object with #return Class[] but in this case, im not using classes.
Thanks.
I am using PHP ReflectionClass to extract as much information about a class as possible. Can I also use this to get return values from functions? Or does that not make sense since reflection only profiles what an object accepts?
You can not rely, if a function has a well defined return value you can simply extract from the source code. Imagine something like this:
return $this->isValid() ? $result : $this->createNullObject();
Thats hard (/impossible) to parse just to get the return value. You can use DocComments instead. #return is the usual tag for that use
/**
* MyMethod
*
* #return int
*/
Call getDocComment() on a ReflectionMethod-object and then parse the docComment.
for internal functions you could use
$reflect = new ReflectionExtension('standard');
echo "<pre>" . $reflect . "</pre>";
When I define an object of a class using new like this
$blah = new Whatever();
I get autocomplete for $blah. But how do I do it when I have $blah as a function parameter? Without autocomplete I am incomplete.
Edit: How do I do it if it's in an include and PDT or Netbeans can't figure it out? Is there any way to declare types for variables in PHP?
Method in first comment is called "type hinting", but you should use that wisely. Better solution is phpDoc.
/**
* Some description of function behaviour.
*
* #param Whatever $blah
*/
public function myFunction($blah)
{
$blah->
// Now $blah is Whatever object, autocompletion will work.
}
You can also use an inline phpDoc comment which does exactly the same thing.
public function myFunction($blah)
{
/* #var $blah Whatever */
$blah->
// Now $blah is Whatever object, autocompletion will work.
}
Try to pass parameter class definition into the function:
function myFunction(Whatever $blah) {
}