Does PHP allow class functions & properties to share the same name? - php

An old colleague of mine wrote this in our code:
public function paginate() {
return $this->paginate;
}
And I was wondering: does this return the function paginate() or the class property $paginate?
I'm guessing the latter, but it is strange that I haven't found any information on this subject.

That returns the class property $paginate.
If it was return $this->someName();
then it returns function someName().

The brackets after a function call in PHP aren't optional, and ordinary methods and functions are not "first class objects" (they can't be manipulated as variables in their own right, as for instance, in JavaScript).
Thus there is no ambiguity, since $this->paginate(); must be a function call, and $this->paginate; must be a variable reference.
However, it is not particularly good practice, and editors, IDEs, etc, will probably highlight it as a warning.
Common practice is for functions and methods to begin with a verb (what it does), and property names to be a noun (what it is). So the property should probably be "pagination", and the method either "paginate" (take the data and create some pagination), or "getPagination" (return the "pagination" property).

Return an object property:
$this->paginate;
vs
Cause an object method to run (function in a class is termed a method)
$this->paginate();

It will return the $paginate property of the class that the function belongs to or ihnerits from another class, if it is declared as public.

Related

PHP callback: Is there an equivalent for ::class for a method of a class?

In PHP it is possible to get a full class name via class name resolution like this:
Example:
namespace Name\Space;
class ClassName {}
echo ClassName::class;
Output: Name\Space\ClassName
This is better than using the string Name\Space\ClassName directly in the code because code introspection especially in IDEs can find an error directly.
I wonder if there is something similar for methods of a class - this would be specifically useful for callback functions.
This is how you can basically can pass a callback:
$a = function($callback,$arg) { return $callback($arg); }
$a('getInfo',5);
Instead of passing a string here (which might change), I would prefer to do something like this:
$a(MyClass::class::getInfo,5);
With I "go to declaration" click in the IDE I could go directly to getInfo plus I see errors in case with method does not exist anymore. Is there a way to achieve what I want to do here?
In fact, you work with callable type. And PHP allows setting method/function name only as a string. But if you use classes and objects you will have a different way to set callback. For example:
$a = function($callback, $arg) {
return call_user_func($callback, $arg));
}
// call a static method of the class with
// using fullname space and method name as a string
$a('Name\Space\MyClass::getInfo',5);
// call a static method of the class
// with using ::class
$a([MyClass::class, 'getInfo'], 5);
// call a method of an object
$myObject = new MyClass();
$a([$myOject, 'getInfo'], 5);
Three possibilities.
(1)
echo `__CLASS__`;
...returns namespace\classname as a string.
(2)
If you're trying to get the namespace\classname from another class, i.e., not the one where you're currently executing code, then I would suggest setting a public property inside each class such as:
public static $classname = __CLASS__;
which you could then access from anywhere as:
ClassName::$classname
Put it in each of your classes. Always use the same property name.
(3)
Have you considered the PHP function debug_backtrace() which returns a call stack with the most recent call at index = 0;
So, if:
$caller = debug_backtrace();
Then, $caller[0]['class'] contains the fully qualified class name, including any namespace, at the point where you called debug_backtrace().
I'm guessing that #2 is the solution that will work for you.
Just thought of a 4th possibility that doesn't depend on you adding any code to each class. Might add some overhead though, but so does my 3rd solution above.
(4)
$declared_classes = get_declared_classes();
This lists all of the classes currently declared within the PHP scope as fully qualified namespace\classname. You could search the returned array for partial string matches within the array and return the whole namespace\classname string.
One thing to keep in mind. You might have duplicates if different namespaces have same-named classes.
I've added this as a comment somewhere else but figured it might warrant an actual answer to this question. If you use:
$callback = [MyClass::class, 'myMethod'];
Then at least one IDE (PhpStorm) will recognize this as the callable that it is, allow you to navigate to it, mention it in "show usages" and automatically change it when it is renamed through a refactor. I use this in my code if, for instance, I reference a method in a test:
$this->mock(MyClass::class, function(MockInterface $mock) {
$mock->shouldReceive([MyClass:class, 'myMethod'][1])->andReturn(10);
});
Not the cleanest syntax, but it's workable.

PHP static methods

I understand that static methods have no access to state of instance objects of their class types and hence referencing $this inside them results in an error.But objects can reference static methods using object to member operator ->
$obj->staticMethod();
and can even pass it their state via paramaters.
$para1 = $obj->para1;
$para2 = $obj->para2;
$obj->staticMethod($para1, $para2);
How is this last example possible when statics are resolved in static context. If someone can explain to me the general behaviour of statics in php code. you can even talk about C related concepts if it will help.
Since you state that you already understand what static means, I'll skip over that.
However, it may still be good to reference PHP's documentation on the static keyword. In particular the following two alerts are important (and hard to glance over, really).
Caution In PHP 5, calling non-static methods statically generates an E_STRICT level warning.
And this one (italic emphasis mine).
Warning In PHP 7, calling non-static methods statically is deprecated, and will generate an E_DEPRECATED warning. Support for calling non-static methods statically may be removed in the future.
So, to cut a long story short: yes, your example will run (for now), because the PHP interpreter will try to fix up your mistake for you. You should however never do this. What the PHP interpreter will do is:
Say your $obj is of type Foo. Then it will read
$obj->staticMethod($para1, $para2);
conclude that staticMethod is static and instead execute
Foo::staticMethod($para1, $para2);
It is of course perfectly fine to pass parameters that are properties of an instance of Foo. It doesn't matter to staticMethod where the parameters come from.
To elaborate a bit more on why this works, while using $this in a static method is not allowed.
You can think of normal methods as static functions that have one extra: they receive an implicit parameter $this. The value of $this is simply the object on which the method is called. Thus, $obj->do($a, $b, $c) is equivalent to calling Foo::do($obj, $a, $b, $c) and naming the first argument of do, $this. This is convenient, because we can now easily define methods that work on an instance of an object without having to explicitly state over and over again that this instance is a parameter of our methods. Great.
Now back to static functions. The only difference with normal methods is that they do not receive this implicit $this parameter. Thus, using $this inside of them is invalid. Not because it is forbidden, but because it does not reference anything. PHP does not (and cannot) have a clue what $this should refer to.
Another way to look at it. Say that our Foo class has two properties: $para1 and $para2, both numbers. Say that you write a method that returns the sum of these numbers. One way is to do this:
public static function sum($para1, $para2) {
return $para1 + $para2;
}
Great. Works. However, it is annoying to have to call it like this
$sum = Foo::sum($obj->para1, $obj->para2);
So, this is what methods are for!
public function sum(/* implicit $this parameter */) {
// write looking up the properties once inside the function, instead
// of having to write it every time we call the function!
return $this->para1 + $this->para2;
}
// ...
$sum = $obj->sum(); // $obj is passed implicitly as $this
Because static functions do not receive an implicit $this parameter, using $this inside of them is like trying to use $undefined when you have never defined it. Thus, invalid.
Static means class members in simple terms , A static data member is accessible within a class regardless object is created or not . The static function are also functions dedicated to whole class . Static function works with static data only bit it can sometimes vary . Though statics are class dedicated, you can access them using object. It is allowed in all languages. Why ? Because of feasibility . If an object is not being able to access static members , that is a limitation.

PHP Reflection: How to know if a method/property/constant is inherited from trait?

I want to exclude all inherited methods from trait(s) from the list that are not overriden in a class
So how to know if a class member is inherited from trait?
Yes, I can check it like this:
if ($trait->hasMethod($methodName)
|| $ref->getTraitAliases()[$methodName] !== null)
{
//
}
But what if the trait method is overriden in a class? How to know it?
One way is to check if method bodies are similar, if so, i may exclude it,
but is there a better way to achieve this?
A simpler way to do this is ReflectionMethod::getFileName(). This will return the file name of the trait, not the class.
For the exotic case where trait and class are in the same file, one can use ReflectionMethod::getStartLine(), and compare this with start and end line of trait and class.
For the exotic case where trait and class and method are all on the same line.. oh please!
I am sorry but the accepted answer by Alma Do is completely wrong.
This solution cannot work even if you overcome the problem of spl_object_hash() values being recycled. This problem can be overcome by refactoring the get*MethodRefs() functions into one function that computes both results and ensures that the ReflectionMethod objects for the trait methods still exist when the analogous objects for the class methods are created. This prevents recycling of spl_object_hash() values.
The problem is, the assumption that "PHP will use same instance for trait method" is completely false, and the appearance of that happening resulted precisely from "lucky" spl_object_hash() recycling. The object returned by $traitRef->getMethod('someName') will always be distinct from the object returned by $classRef->getMethod('someName'), and so will be the corresponding instances of ReflectionMethod in collections returned by ->getMethods(), regardless of whether method someName() is overriden in the class or not. These objects will not only be distinct, they won't even be "equal": the ReflectionMethod instance obtained from $traitRef will have the name of the trait as the value of its class property, and the one obtained from $classRef will have the name of the class there.
Fiddle: https://3v4l.org/CqEW3
It would seem that only parser-based approaches are viable then.
Important notes
This is only because of "academical" interest, in real situation you should not care about - from where method was derived as it contradicts the idea of traits, e.g. transparent substitution.
Also, because of how traits are working, any kind of such manipulations might be considered as "hacky", so behavior may differ across different PHP versions and I would not suggest to rely on that.
Distinction: difficulties
In reflection for PHP, there is getTraits() methods which will return ReflectionClass instance, pointing to reflection of trait. This may be used to fetch all methods, declared in traits, which are used in the class. However - no, it will not help in your question as there will be not possible to distinct which methods were then overridden in the class.
Imagine that there is trait X with methods foo() and bar() and there is class Z with method bar(). Then you will be able to know that methods foo() and bar() are declared in trait, but if you will try to use getMethods() on class Z - you will obviously get both foo() and bar() as well. Therefore, directly you can not distinct the case.
Distinction: work-aroud
However, yes, there is a way to still make it work. First way - is - like you've mentioned - try to investigate source code. It's quite ugly, but in the very end, this is the only 100% reliable way to resolve the matter.
But - no, there is another, "less ugly" way - to inspect instances on ReflectionMethod classes, that are created for class/traits methods. It happens that PHP will use same instance for trait method, but will override that one which is for the method, declared in class.
This "inspection" can be done with spl_object_hash(). Simple setup:
trait x
{
public function foo()
{
echo 'Trait x foo()';
}
public function bar()
{
echo 'Trait x bar()';
}
}
class z
{
use x;
public function foo()
{
echo 'Class foo()';
}
}
And now, to fetch hashes for both cases:
function getTraitMethodsRefs(ReflectionClass $class)
{
$traitMethods = call_user_func_array('array_merge', array_map(function(ReflectionClass $ref) {
return $ref->getMethods();
}, $class->getTraits()));
$traitMethods = call_user_func_array('array_merge', array_map(function (ReflectionMethod $method) {
return [spl_object_hash($method) => $method->getName()];
}, $traitMethods));
return $traitMethods;
}
function getClassMethodsRefs(ReflectionClass $class)
{
return call_user_func_array('array_merge', array_map(function (ReflectionMethod $method) {
return [spl_object_hash($method) => $method->getName()];
}, $class->getMethods()));
}
In short: it just fetches all methods from class trait (first function) or class itself (second function) and then merges results to get key=>value map where key is object hash and value is method name.
Then we need to use that on same instance like this:
$obj = new z;
$ref = new ReflectionClass($obj);
$traitRefs = getTraitMethodsRefs($ref);
$classRefs = getClassMethodsRefs($ref);
$traitOnlyHashes = array_diff(
array_keys($traitRefs),
array_keys($classRefs)
);
$traitOnlyMethods = array_intersect_key($traitRefs, array_flip($traitOnlyHashes));
So result, $traitOnlyMethods will contain only those methods, which are derived from trait.
The corresponding fiddle is here. But pay attention to results - they may be different from version to version, like in HHVM it just doesn't work (I assume because of how spl_object_hash is implemented - an either way, it is not safe to rely on it for object distinction - see documentation for the function).
So, TD;DR; - yes, it can be (somehow) done even without source code parsing - but I can not imagine any reason why it will be needed as traits are intended to be used to substitute code into the class.

How to define constant in class constructor?

Can I define a class constant inside the class constructor function ?
(based on certain conditions)
That goes against the idea of class constants - they should not be dependent on a specific instance. You should use a variable instead.
However, if you insist on doing this, are very adventurous and can install PHP extensions, you can have a look at the runkit extension that allows to modify classes and their constants at runtime. See this doc: http://www.php.net/manual/en/function.runkit-constant-add.php
I don't think you can.
It wouldn't make sense, either - a class constant can be used in a static context, where there is no constructor in the first place.
You'll have to use a variable instead - that's what they're there for.
Try look here:
http://php.net/manual/en/language.oop5.constants.php
http://php.net/manual/en/language.oop5.static.php
Hope this helps.
As far as standard instance constructors go, there is no way to do this, and as others have pointed out, it wouldn't make sense. These constructors are called per created object instance, at the point they are created. There is no guarantee this constructor would get called before some code tried to access the constant. It also doesn't make sense in that the code would get called over and over again each time a new instance was constructed, whereas a const should only get set once.
It would be nice if PHP either offered some kind of static constructor that let you set the value one time for uninitialized constants, or allowed more types of expressions when defining constants. But these are not currently features of PHP. In 2015 an RFC was made that proposed adding static class constructors, but it is, at the time of me writing this answer, still in the draft status, and has not been modified since 2017.
I think the best alternative for now is to not use constants in this kind of scenario, and instead use static methods that return the value you want. This is very simple in that it only uses the PHP language features as is (not requiring any special extensions), these static methods can be called in the standard way, and you don't need to hack the autoloading process to call some kind of initializer function that sets static variables. The method might need to rely on private static variables in order to make sure the same instance is returned every time, if an object instance is being returned. You would need to write the implementation of this method to be constant like in the sense that it will always return the same thing, but takes advantage of being able to do things you can't do with a constant, like return on object instance or rely on complex expressions or function calls. Here is an example:
final class User
{
/** #var DefinitelyPositiveInt|null */ private static $usernameMaxLength;
public static function getUsernameMaxLengthConst(): DefinitelyPositiveInt
{
if ($usernameMaxLength === null) {
$usernameMaxLength = new DefinitelyPositiveInt(40);
}
return $usernameMaxLength;
}
}
$usernameInput.maxLength = User::getUsernameMaxLengthConst();
This is still not a perfect solution because it relies on the programmer to write these in a constant like way when that is desired (always returning the same value). Also, I don't like that the best place to document the fact that it is a const is in the method name, thus making it even longer to call. I also don't like that you now have to call it as a method instead of just accessing a property, which would be syntactically nicer.
This example is essentially an implementation of a singleton, but sometimes the purpose of a singleton is to be a constant rather than just a singleton. What I mean is, you might want the instance to always exist, and it might be an immutable type (none of the properties are public or mutable, only having methods that return new objects/values).
I am sorry to break it to you but it is not possible in vanilla PHP.
I am not very sure about frameworks or extensions but I am sure that it is not possible in vanilla PHP.
I recommend you to use variables instead.
You still can't, but maybe some of these (progressively weirder) ideas (just ideas, not true solutions) will work for you:
(1) You could use a private property, with a public getter method. The property cannot be modified outside the class, such as constants, but unfortunately it is accessed as a method, not as a constant, so the syntax is not the same.
class aClass{
private $const;
function __construct($const){
$this->const=$const;
}
function const(){
return $this->const;
}
}
$var1=new aClass(1);
echo $var1->const(); //Prints 1
(2) If you really want this value to be accessed as constant from outside, you can use define () inside the constructor. Unfortunately it doesn't get tied to the class or object name (as it do when you use const, using for example myClass::myConst). Furthermore, it only works if you create a single instance of the class. The second object you create is going to throw an error for redefining the constant, because is untied.
class otherClass{
function __construct($const){
define('_CONST',$const);
}
function const(){
return _CONST;
}
}
$var2=new otherClass('2');
echo $var2->const(); //Prints 2
echo _CONST; //Prints 2
#$var3=new aClass('3'); //Notice: Constant _CONST already defined
echo _CONST; //Still prints 2!
(3) Perhaps that last problem can be solved by giving variable names to the constants, related to the object to which they belong. This may be a bit weird... but maybe it works for someone.
class onemoreClass{
private $name;
function __construct($const,$name){
$this->name=$name;
$constname=$this->name."_CONST";
define($constname,$const);
}
function const(){
return constant($this->name.'_CONST');
}
}
$name='var4';
$$name=new onemoreClass(4,$name);
echo $var4->const(); //Prints 4
echo var4_CONST; //Prints 4
$name='var5';
$$name=new onemoreClass(5,$name);
echo $var5->const(); //Prints 5
echo var5_CONST; //Prints 5

How to find places where a non-static method is called?

In the case of the following example,
I can not easily find the places where get() of Book class is called by searching files with get.
Because there are a lot of get which do not belong to Book class.
class Book {
function get() {
}
}
class Pen {
function get() {
}
}
$obj = new Pen;
$obj->get();
$obj = new Book;
$obj->get();
But if I use just functions or static methods like the following codes,
I can easily find the places by searching files with Book_get or Book::get.
And if I use functions, I can find both where the function is called and where the function is defined by searching only with Book_get.
function Book_get() {
}
function Pen_get() {
}
Book_get();
Pen_get();
class Book {
static function get() {
}
}
class Pen {
static function get() {
}
}
Book::get();
Pen::get();
When I use non-static methods, how can I easily find the places where they are called?
Or is it better to use functions or static methods instead of non-static methods as possible?
You can always temporarily rename get to something like xget and rebuild to find the calling points.
When I use non-static methods, how can I easily find the places where they are called?
A class member function can be called in a number of ways,
Through instance of class
Through polymorphic behavior(dynamic dispatch)
For first case, any reasonably good code analysis tool or IDE will be able to tell you the class from which the function is being called depending on type of the object, but
I guess there is no easy way to track the second case without examining the code, I doubt any of the code analysis tools are intelligent enough to tell you exactly which class method is being called(Source Insight surely doesn't) because the dispatch is dynamic not compile time.
Is it better to use functions or static methods instead of non-static methods as possible?
To use or not use a static method needs much deeper thought than just to be able to find functions in a search.
Static functions do not have this pointer so you cannot access non static members inside it.They can only operate on static members of the class.
Switching to a better IDE is the simplest solution. Eclipse CDT for example allows you to view the caller hierarchy and find all call sites of a method. (Although, advanced cases of templates and inheritance might still make it hard to figure)
If your method needs access to data in this->, then you have to make it a non-static method. Then the object needs to be instantiated (via new).
If all your method uses is data contained in function parameters, then consider making your method static. Or create a separate class with static methods only.
Book::get();
Pen::get(); this will be the best to use in nonstatic

Categories