Finding the class of an instance in PHP - php

This is just an example to illustrate my issue. Quite often, I am looking for (vendor) code that executes a method, but end up in the interface (which I guess is implemented by the code I am looking for).
In a Symfony app, I have a function Example()that uses $logger, which is typehinted with LoggerInterface. I use the correct interface by adding to my file: use Psr\Log\LoggerInterface;. In my function I use $logger to log an error with the method error() like so:
public function Example(LoggerInterface $logger)
{
$logger->error('There was some error.')
}
When I open the file that contains the LoggerInterface I can see how this method:
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* #param string $message
* #param array $context
*
* #return void
*/
public function error($message, array $context = array());
This can be useful for the documentation and for seeing which arguments one must pass.
My question: how do I find the method that does the actual work (i.e. that is being executed) and how does the $logger 'finds' this through the interface?
In a more generic PHP example, when I need a dateTime object I will use new DateTime(); (with a use statement: use DateTime;). Then I could call the method format() on it. When I want to find out exactly what format() does, looking for it in the class DateTime, all I find is:
/**
* Returns date formatted according to given format.
* #param string $format
* #return string
* #link https://php.net/manual/en/datetime.format.php
*/
public function format ($format) {}
Again I wonder: how to find the method doing the work?

Psr\Log\LoggerInterface is, as its name suggests, an interface. This means that it specifies the methods an inheriting class must implement, but – as you've seen – it doesn't provide any code for those methods.
Any class written to implement Psr\Log\LoggerInterface must include all the methods listed in the interface. Any such class will satisfy the type declaration in the method signature.
The actual class of your object can be determined by running get_class() on the object in question, e.g.
public function Example(LoggerInterface $logger)
{
$logger->error("I am an instance of class " . get_class($logger));
}
With respect to native PHP classes, although the documentation may be written to look like they are standard PHP classes with methods and properties, this is not the case. They are written in C, which you can find in the repository.
Taking your example of DateTime::format(), it's first defined as a method of the DateTimeInterface. This is implemented by the DateTime class, where it is simply specified as an alias to the date_format method. Unless you're very good with C, I'd suggest sticking to the documentation

Multi-tier question, deserves a multi-tier answer.
1. Configuration
Specifically for logger, it can be any logger that follows Psr\Log standards, but symfony is configured to use monolog.
You can see detail on: https://symfony.com/doc/current/logging.html (disclaimer: I'm not symfony expert but this looks logical).
So - logger is whatever you configure.
2. Programming style
When you are programming - anywhere inside a function and want to know exact instance of logger (or any other object), you can call get_class() function and get a specific instance class name.
Details on: https://secure.php.net/manual/en/function.get-class.php
3. Debugger
You can use Xdebug, add breakpoint to specific function and in variable view check instance class name.
4. PHP native objects
You can find exact functionality in PHP source code: https://github.com/php/php-src

Related

Should I use `DateTimeInterface` in my php project?

Recently, I discovered that there is a DateTimeInterface. As I was working with \DateTime and \DateTimeImmutable, I thought that it'd be good to typehint for.
Yet on the Changelog on php.net it says that since 5.5.8:
Trying to implement DateTimeInterface raises a fatal error now. Formerly implementing the interface didn't raise an error, but the
behavior was erroneous.
This reads that I never be able to implement my own CustomDateTime class implementing the DateTimeInterface, which seems rather odd.
Should I use the DateTimeInterface in my userland code?
My gut feeling tells me not to. Yet it also doesn't feel right to typehint the object, i.e.
#var \DateTime|\DateTimeImmutable|\MyCustomDateTime
You can use the DateTimeInterface typehint when you expect either one of the native DateTime variants, e.g. \DateTime or \DateTimeImmutable.
But as the docs say
It is not possible to implement this interface with userland classes.
So if you plan to implement \DateTimeInterface with your own implementation, this will not work, e.g.
class MyDateTime implements \DateTimeInterface {} // will raise an error
However, you can create your own interface and adapt the native DateTime classes.
interface MyDateTime { /* some methods */ }
class NativeDateTime implements MyDateTime
{
private $dateTime;
public function __construct($args = 'now') {
$this->dateTime = new \DateTimeImmutable($args);
}
/* some methods */
}
Or you can extend the native DateTime variants, which will then implement the DateTimeInterface obviously, e.g.
class MyDateTime extends \DateTimeImmutable
{
/* your modifications */
}
var_dump(new MyDateTime instanceof \DateTimeInterface); // true
Details why you cannot implement your own classes implementing \DateTimeInterface:
https://github.com/php/php-src/pull/512
https://www.mail-archive.com/internals#lists.php.net/msg79534.html
tl;dr core functions that accept DateTime and DateTimeImmutable (DateTimeInterface basically) operate directly on timelib structures hence they will break if you pass them a user-defined class. There's a workaround though - it's to always call user-defined class's method directly from built-in functions, so if you would call (new DateTime())->diff(new UserDefinedDateTime()) it would call UserDefinedDateTime#diff in the end which would need to implement the logic.
I would say you should not.
The \DateTimeInterface is an implementation detail of ext/date that should not have been exposed to userland code.
See the RFC created for removing it: https://wiki.php.net/rfc/drop-datetimeinterface
You are encouraged to type hint against DateTimeInterface when you accept
DateTime
DateTimeImmutable
Any class derived from these
You can however not implement DateTimeInterface without extending from either DateTime or DateTimeImmutable due to internal details.
You can ignore https://wiki.php.net/rfc/drop-datetimeinterface as by now - years after the question - we know that the community decided against removing the interface.

PHP: documentation / hinting via #var with multiple classes/interfaces

I am making usage of
/* #var $var Type */
really often for NetBeans can then autocomplete methods and stuff in code.
Still I think its a very useful feature but sometimes I got objects of
classes extending one more class and implementing multiple interfaces.
Or I even got a transitive class hierarchy.
I don't know a way to tell NetBeans that it shall be using autocomplete for
all these interfaces and upper-layer parent classes.
I would like to do so for of course every of these interfaces / classes got
dedicated methods (which are defined somewhere in case of interfaces...)
I tried something like this:
/* #var $var TypeA|\TypeB|\TypeC */
because I saw NetBeans will generate a similar documentation for methods returning
different class objects due a switch/case. But this seems to work only for the
#return notation.
I also tried
/* #var $var TypeA|TypeB */
Also not working...
NetBeans will autocomplete the last told Type in this case but not a combination of both/all told classes.
How can I document so my autocomplete works as desired (a summary of methods of all classes /interfaces I listed)?
regards!
If I understand you correctly, you are asking to chain hint through your PHP code.
The problem is netbeans has no way of knowing what an object actually is; unless you tell it. The solution is to use the #property command in your object decleration to forward type define the objects members , be it a class or interface.
/**
#property classMyClass1 $clsMyClass1
#property classMyClass2 $clsMyClass2
*/
class baseClass{
public $clsMyclass1;
public $clsMyClass2;
public function __construct() {
$this->clsMyClass1 = new classMyClass1();
$this->clsMyClass2 = new classMyClass2();
}
}
$foo = new baseClass();
Now when you type your code in netbeans it will know what hinting to display on your last typed object
$foo->clsMyClass1->
So long as each class has a forward property decleration you can chain as long as you want
$foo->class1->class2->class3->...
The above code would need the autoload() function to load the correct class files....
Hope this helps you!

How to correctly document that a method parameter should be a class name that implements a certain interface?

I'm using PHPDoc. I've got a method that accepts a string parameter. That string should be the name of a class that implements a certain interface, say, IMyInterface.
Should I do:
/**
* #param string $class_name
*/
public function myMethod($class_name) {}
or
/**
* #param IMyInterface $class_name
*/
public function myMethod($class_name) {}
I'm guessing that since classes and interfaces aren't first class in PHP, it's probably the latter. But something seems wrong about both options.
I used ApiGen for a project I did a while back and I found it best to use the class name as it created linking within the documentation to the pages for those particular classes. I haven't used PHPDoc, but perhaps it has similar functionality and make your documentation a little more accessible.
/**
* Constructor function.
*
* Creates a new user object with data provided.
*
* #return void
* #param mixed An array or object of user information to be read in.
* #param Permissions An instance of a Permissions object to associate with the user.
*/
public function __construct($data,$perms) {
...
}
In your use case, "string" is correct, because you are telling the reader exactly what kind of datatype to pass in. If a user actually tried passing a concrete class instance of an IMyInterface implementer, your code is no doubt going to choke.
If your method is only built to accept a certain list of strings that represent a list of usable interfaces, then I'd suggest saying this outright in the method's long description, not in the one parameter's description. I would also utilize the #see tags to provide links to the docs of all the interfaces this method is built to accept. That way, your #param tag truly tells the reader "dude, I gotta have a string", your method description explains how the method will take that string and correlate it to a defined interface, and the #see tags will help the reader jump directly to any/all of the interfaces themselves.
Regarding IDE autocompletion, some IDEs can interpret "/** #var IMyInterface $localMethodVar */" inside your method code, and would then provide autocompletion on $localMethodVar as if it were a defined instance of IMyInterface.

How to generate or modify a PHP class at runtime?

The schmittjoh/cg-library seems what I need, but there is no documentation at all.
This library provides some tools that you commonly need for generating
PHP code. One of it's strength lies in the enhancement of existing
classes with behaviors.
Given A class:
class A {}
I'd like to modify, at runtime of course and with some cache mechanism, class A, making it implementing a given interface:
interface I
{
public function mustImplement();
}
... with a "default" implementation for method mustImplement() in A class.
You can also use a Role Object pattern and good old aggregation.
Instead of having smart Entities that contain all your business logic, you make them dumb and move all the business logic into Roles that aggregate the dumb Entities then. Your behaviors are then first-class citizens living inside the Roles.
Example:
interface BannableUser
{
public function ban();
}
Having an interface with one particular behavior follows the Interface Segregation Principle. It also dramatically increases possible reuse since you are more likely to reuse individual behaviors than an Entity with an application-specific collection of behaviors.
Now to implement that, you create an appropriate Role Class:
class BannableUserRole implements BannableUser
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function ban()
{
$this->user->isBanned = true;
}
}
You still have a User entity but it's completely stripped of all behaviors. It's essentially just a bag of Getters and Setters or public properties. It represents what your System is. It's the data part, not the interaction part. The interaction is inside the Roles now.
class User
{
public $isBanned;
// … more properties
}
Now assuming you have some sort of Web UI, you can do the following in your controller:
class BanUserController implements RequestHandler
{
// …
public function handleRequest(Request $request)
{
$userId = $request->getVar('user_id');
$user = $this->userRepository->findById($userId);
$bannableUser = new BannableUserRole($user);
$bannableUser->ban();
}
}
You can decouple this further by moving the actual lookup of the User and assignment of the Role into a UseCase class. Let's call it Context:
class BanUserContext implements Context
{
public function run($userId)
{
$user = $this->userRepository->findById($userId);
$bannableUser = new BannableUserRole($user);
$bannableUser->ban();
}
}
Now you have all the business logic inside your Model layer and fully isolated from your User Interface. The Contexts are what your system does. Your Controller will only delegate to the appropriate Context:
class BanUserController implements RequestHandler
{
// …
public function handleRequest(Request $request)
{
$this->banUserContext->run($request->getVar('user_id'));
}
}
And that's it. No need for Runkit or similar hackery. The above is a simplified version of the Data Context Interaction architectural pattern, in case you want to further research this.
Note: OP needs PHP 5.3 (it was not tagged that way before), this question is a general outline for PHP 5.4.
You can do that with defining the interface and adding traits that contain the default implementation for those interfaces.
Then you create a new class definition that
extends from your base-class,
implements that interface and
uses the default traits.
For an example, see Traits in PHP – any real world examples/best practices?
You can easily generate that class definition code and either store it and include it or eval it straight ahead.
If you make the new classname containing all the information it consists of (in your case the base classname and the interface), you can prevent to create duplicate class definitions easily.
This works without any PHP extension like runkit. If you bring serialize into the play, you can even overload existing objects at runtime with the new interface in case they can serialize / deserialize.
You can find a code-example that has been implementing this in:
DCI-Account-Example-in-PHP / src / DCI / Casting.php (usage)
I needed a tool to edit PHP classes (specifically Doctrine Entities), I could not find it so I created one that might help you, I documented it heavily. So if you want to give it a try, I'll happily help.
Here it is, SourceEditor
It gives you an API like this:
/* #var $classEditor DocDigital\Lib\SourceEditor\PhpClassEditor */
$classEditor->parseFile($classPath);
$classEditor->getClass('a')->getMethod('b')->addAnnotation('#auth Juan Manuel Fernandez <juanmf#gmail.com>');
$classEditor->getClass('a')->getAttribute('attr')->addAnnotation('#Assert\Choice(...)');
$classEditor->getClass('a')->addAttribute($attr2);
$classEditor->getClass('a')->addUse('use DocDigital\Bundle\DocumentBundle\DocumentGenerator\Annotation as DdMapping;');
$classEditor->getClass('a')->addConst(' const CONSTANT = 1;');
file_put_contents($classPath, $classEditor->getClass('a')->render(false));
Runkit extension can help you
Runkit_Sandbox — Runkit Sandbox Class -- PHP Virtual Machine
Runkit_Sandbox_Parent — Runkit Anti-Sandbox Class
runkit_class_adopt — Convert a base class to an inherited class, add ancestral methods when appropriate
runkit_class_emancipate — Convert an inherited class to a base class, removes any method whose scope is ancestral
runkit_constant_add — Similar to define(), but allows defining in class definitions as well
runkit_constant_redefine — Redefine an already defined constant
runkit_constant_remove — Remove/Delete an already defined constant
runkit_function_add — Add a new function, similar to create_function
runkit_function_copy — Copy a function to a new function name
runkit_function_redefine — Replace a function definition with a new implementation
runkit_function_remove — Remove a function definition
runkit_function_rename — Change the name of a function
runkit_import — Process a PHP file importing function and class definitions, overwriting where appropriate
runkit_lint_file — Check the PHP syntax of the specified file
runkit_lint — Check the PHP syntax of the specified php code
runkit_method_add — Dynamically adds a new method to a given class
runkit_method_copy — Copies a method from class to another
runkit_method_redefine — Dynamically changes the code of the given method
runkit_method_remove — Dynamically removes the given method
runkit_method_rename — Dynamically changes the name of the given method
runkit_return_value_used — Determines if the current functions return value will be used
runkit_sandbox_output_handler — Specify a function to capture and/or process output from a runkit sandbox
runkit_superglobals — Return numerically indexed array of registered superglobals
You can look: https://github.com/ptrofimov/jslikeobject
Author implemented dynamic JS-like objects with support of inheritance.
But it is more like a joke than real proposition.

What is the proper way to document files, classes and constructors?

What is the most useful/most standard/least surprising way to consistently write comment blocks for constructors and classes and files containing just a single class?
Comment blocks for classes, not constructors
Comment blocks for constructors, not classes
Comment blocks for both constructors and classes -> In that case what sort of details should go in each?
And then the file itself? Does this need a comment block if it just contains a single class? What details should go there?
I want to try and avoid, as much as possible, repetition between class, constructor and file comment blocks.
This is highly depending on your context and the assumed skill level of the people you work with or the people that come after you.
If you publish a framework, a library or something of the sort you usually assume that your user are of all skill levels so you might want to document as much trivial crap as possible to reduce the load of questions your community has to handle.
Let me start of with an example where I think documentation can be a major pain.
What do you absolutely need
If you want to use PHPDoc you need a file doc block and another doc block after that (usually the class doc block).
Those **need* to have a #package Tag. Everything else is optional.
I'd go so far and say that even the #package Tag is optional since you might be able to automatically generate it for project. And if i remember correctly PHPDoc lets you even set a default package for everything that doesn't have a tag.
For documentation in general let me start of with an example (a longer example is at the end):
How many times can you explain what "uri" means:
Note that for getUri it is explained what URI stands for (just to have something to talk about in the comment I'd assume) while it isn't in isAbsUri because there you can at least say "abs means absolute" twice.
If you are not an open source project (or need to ship COMPLETE!!!11eleven api documentation):
I'd strongly suggest to use proper, long and descriptive class, variable and method names instead of documentation.
There is no gain in writing something again in the doc blocks and since it is 2011 and we have 120 char wide terminals and autocompletion there is just no need anymore to abbreviate everything for the sake of saving some chars.
I'd even argue that documenting trivial things hurts you and your team by forcing you to waste time on things nobody gets value from you get into a habit of always writing trivial docs and not reading them anymore.
A good comment should explain WHY something was done while the code its self should explain HOW without needing further comments.
My favorite example for redundant docs is this one:
class myClass {
/**
* Constructor
*/
public function __construct() {
}
Some guidelines say you HAVE to document EVERYTHING and you end up with people stating the obvious again and again.
This adds no value but wastes time when reading the code.
An example for proper naming:
class Person {
/**
* Set a persons weight in Kilogram
*
* #param float $kg Weight in Kilogram
*/
public function setWeight($kg) {}
This code is easy to document because you need to explain what "kg" means because some people might use a different system and you can't google for "kg".
I'm in favor of writing
class Person {
/**
* #param float $kilogram
*/
public function setWeight($kilogram) {}
The doc block is superfluous because calling setWeight on Person can REALLY be expected to set the Weight on a Person. No need to write that out again.
Using $kilogramm as a parameter also saves you the trouble of explaining it in the docs and I'd say, depending on your environment, everyone can be expected to google for "kilogram" if he really doesn't know the measurement unit.
#PHPDoc documentation
All my humble opinion of course
If you don't use type-hinting always use #param tags.
Always use #return tags
Don't use #author tags at all. Collection code ownership is more valuable and the information is in the source control repository anyways.
Only use #copyright tags if you have to. I like only having a LICENSE file but I'm not a lawyer so it might be necessary.
Inline comments:
public function generateReport() {
// get the db connection
$reg = WhateverGlobalStorage::get(“db“);
// auth
if(!$reg->getOne("SELECT view_report FROM USER ...")) {}
// template
$id = $reg->getOne("select ... ");
// render
new ReportTemplate($id); // ...
}
If those are separate "blocks" just move them to descriptive named functions
public function generateReport() {
$this->checkAuthentication();
$template = this->createReportTemplate();
$this->renderReport($template);
}
// Not perfect but at least you can grasp what the method does much quicker
Additional resources:
Slides of a presentation I gave on the subject on some conferences: Slideshare: clean-code-stop-wasting-my-time
And additional small, little older, rant: they-told-you-to-document-everything-they-lied
Book references:
Clean Code: A Handbook of Agile Software Craftsmanship
Refactoring: Improving the Design of Existing Code
A longer example
abstract class xyzRequest {
/**
* Initializes this xyzRequest.
*
* Available options:
*
* * logging: Whether to enable logging or not (false by default)
*
* #param xyzEventDispatcher $dispatcher An xyzEventDispatcher instance
* #param array $parameters An associative array of initialization parameters
* #param array $attributes An associative array of initialization attributes
* #param array $options An associative array of options
*
* #return bool true, if initialization completes successfully, otherwise false
*
* #throws <b>xyzInitializationException</b> If an error occurs while initializing this xyzRequest
*/
public function initialize(xyzEventDispatcher $dispatcher, $parameters = array(), $attributes = array(), $options = array()) {
Lets see, line by line, what that documentation tells you.
(I'm joking around here a little bit to get my point across)
* Initializes this xyzRequest.
So calling ->initialize on a xyzRequest initializes that request? Really? Ok then, if you say so!
* Available options:
*
* * logging: Whether to enable logging or not (false by default)
We are told the options for the third parameter, not for the second or third param but maybe we know those if we know the framework? (Since we are not able to figure out what ->initialize does without someone telling use we might not be that smart...)
* #param xyzEventDispatcher $dispatcher An xyzEventDispatcher instance
Yeah, the type-hint is there. So if the method expects a "xyzEventDispatcher instance" we need to pass in a "xyzEventDispatcher instance". Good to know.
* #param array $parameters An associative array of initialization parameters
* #param array $attributes An associative array of initialization attributes
* #param array $options An associative array of options
Ok. So it's not a linear array. But that I need to pass "initialization parameters" to an "initialize" method I could have figured out.
Still no clue what I actually need to pass in there but as long as its documented it has to be fine!
* #return bool true, if initialization completes successfully, otherwise false
So a boolean return value is "true" for "good" and "false" for bad".
* #throws <b>xyzInitializationException</b> If an error occurs while initializing this xyzRequest
*/
So an exception is thrown if an error occurs while we are doing what the function is named?
So exceptions are used for error cases. Ok. Good to know.
Doesn't tell me the difference between return false and an exception.
The #throws its self is fine because it adds information
Btw: Why is this BOLD and not a #link
Personally, I only comment in the constructors if there is something special to comment about it (like a special initialization).
I wouldn't say that's the "most useful" way to go, but it keeps the code neat, and repeating two times the same thing isn't really needed (if that's your concern).
Comment everything - files (authorship, copyright, description etc), classes (description, code examples), methods and properties. Here is a good example with phpDoc comments.
Personally I think that class and method documentation is the most important documentation around. When I write code I want the help of my IDE when the code completion shows me the documentation belonging to a method. This way I can easily find the method I need.
Since I try to keep the explicit initialization of classes to a minimum, I don't user constructor comments. Hence, I try to avoid the use of constructors itself.
The code in a method or function should be as clear as possible by using declarative variable names and keeping them so small as possible. Only when I do something unexpected, by example for integration issues I comment them.

Categories