Can I extend IDEs suggestions by creating class collisions - php

If a library I use, have a class that extends 2 other classes by the use of __call(), only the main extended class gets it's methods listed in the objects suggestions.
I noticed that if I make another php file in the project, where I put a class with the same name and namespace, and let it extend the other class, the IDE don't know witch one of them I'm referring to and gives me the suggestions for both of them, that way it suggests the methods from both of the extended classes.
This works sometimes, but in some case the IDE is to smart, and somehow know that my class isn't the real one, and only shows methods from the main extendsion.
Is there a better way to tell the IDE that a class in the library have more functions that it seams? Or a way that at least works every time?
Example:
<?php // index.php
include(__DIR__ . "/lib.php");
$c = new c();
echo $c->s_a();
echo $c->s_b(); // Accepted by the IDE
$d = new d();
echo $d->s_a();
echo $d->s_b(); // Not acceted by the IDE
<?php // lib.php
class a {
function s_a() { return "a";}
}
class b {
function s_b() { return "b";}
}
class c extends a {
public $b;
function __construct() {
$this->b = new b();
}
function __call($name, $arguments) {
return call_user_func_array(array($this->b, $name), $arguments);
}
}
class d extends c {}
<?php // fake.php
class c extends b {};
For $c the IDE don't know if it should use class c from lib.php or from fake.php, so it gives be a list with the methods of both.
For $d the that is of class d that extends c, it somehow know that its class c in file lib.php, so $d->s_b() are not sugested.

Related

Alias inexistent class names in php

Consider the following code:
use ReplacementClass;
class A extends ReplacementClass {
}
The ReplacementClass name in this code should only be a placeholder, an undefined, inexistent class. At runtime, or before runtime, I would like to alias this inexistent class, with a dynamically set existing class, for my code to work. Is there any way in PHP to do this?
Why I would like to achieve this, is that A defined in the above example, is a class in a project plugin, which I would like to make portable, so is ReplacementClass in the original plugin. I would like to keep an option for the team, to extend on these classes, and add new functionalities to them, which are only needed in the specific project that they are working on.
In the above situation, if both of those are real classes, I could extend a B class with A, and add the new functionalities in B, and I could also extend ReplacementClassSpecific with ReplacementClass and add new functionalities to it, but given the single inheritance of PHP, I couldn't extend both.
One way you could do this is with class_exists, and adding a dummy placeholder if it doesn't exist.
But ideally I'd suggest you look into Facades like Laravel uses. This way you can be flexible with implementations, without relying on inheritance.
see it online https://ideone.com/pWf8QU
/* // unhide this to see the two behaviours
class ReplacementClass {
public function foo() {
return "foo";
}
public function bar() {
return "bar";
}
}*/
if(!class_exists('ReplacementClass')) {
class MyReplacementClass {
public function foo() {
echo " foo does not exist, this is a placeholder";
}
public function bar() {
echo " bar does not exist, this is a placeholder";
}
}
}
else {
class MyReplacementClass extends ReplacementClass {
}
}
class FooBar extends MyReplacementClass {
}
$x = new FooBar();
echo $x->foo() . $x->bar() . "\n";
You could use eval() for this. But this is very dirty.
eval("class $className extends $parentClassName {}");
Example
class Foo {}
$className = 'Bar';
$parentClassName = 'Foo';
eval("class $className extends $parentClassName {}");
$bar = new Bar();
var_dump($bar); // gives 'object(Bar)#1 (0) {}'
var_dump($bar instanceof Bar); // gives bool(true)
var_dump($bar instanceof Foo); // gives bool(true)
Caution! Using eval is inefficient and can be very dangerous. Consult the documentation before even thinking about using it.
It would be better to reconsider your use case. There is literally nothing I can think of which would require a fully dynamic class name. If you import your library to a code base at that point you should know what class name is expected and at that point you could extend your parent class with a class of that name.

How can I conditionally make a class use a trait if it exists?

I want to be able to use the trait if it's available.
Obviously i cannont define that inside the class itself (syntax Error)
//fails
include_once('myTrait.php');
class foo
{
var $bar;
if (trait_exists('myTrait')) {
use myTrait;
}
}
//also fails
foo use myTrait;
//also fails
$f = new foo();
$f use myTrait;
//also fails
$f = new foo() use myTrait;
Ideal case scenario would be something like this:
class foo
{
var $bar;
}
if (file_exists('myTrait.php')) {
include_once('myTrait.php');
//make class foo use myTrait;
}
$f=new foo();
Having hard time finding documentation and traits doesn't seems very popular but in my particular case they are very useful. I also try to keep resource as low a possible by only including files if needed.
Hints, documentation and explanation welcome as usual.
The closest my search brought me was in this article http://brendan-bates.com/traits-the-right-way/
Let's say a few of these controllers (but not all of them) require a
database connection. To keep performance up, we shouldn't give every
controller the database connection. What we could do is write an
abstract class which extends BaseController which provides a database
connection. But, in the future, what if an object that is not a
controller requires a database connection? Instead of duplicating this
logic, we can use horizontal reuse.
A simple trait can be created:
trait DatabaseAware
{
protected $db;
public function setDatabase($db)
{
$this->db = $db;
}
protected function query($query)
{
$this->db->query($query);
}
}
This trait now provides classes with common database functionality.
Any class which requires a database connection, be it a controller or
a manager (or anything), can use this trait:
class IndexController extends BaseController
{
use DatabaseAware;
public function indexAction()
{
$this->query("SELECT * FROM `someTable`");
}
}
Where as I implement traits depending on the needs of my different objects. Database connection, debugging reporting, etc.
Easy!
Trait
A trait that might be available or not, will be either used or not, but will eventually help to implement an interface:
<?php
trait BarTrait
{
public function bar()
{
return 'Hey, I am your friend!';
}
}
Interface
An interface we are looking to implement:
<?php
interface BarInterface
{
/**
* #return string
*/
public function bar();
}
Class using trait
A class FooUsingBarTrait which uses a trait BarTrait to implement the aforementioned interface:
<?php
class FooUsingBarTrait implements BarInterface
{
use BarTrait;
}
Class not using trait
A class FooNotUsingBarTrait which does not use a trait BarTrait, but instead implements the aforementioned interface itself:
class FooNotUsingBarTrait implements BarInterface
{
public function bar()
{
return 'Hey, I am one of your friends!';
}
}
Conditionally create class definition
Finally, conditionally define a class Foo, depending on whether a trait BarTrait exists or not:
<?php
if (trait_exists(BarTrait::class) {
class Foo extends FooUsingBarTrait
{
}
} else {
class Foo extends FooNotUsingBarTrait
{
}
}
Create your instance
$foo = new Foo();
$foo->bar();
var_dump(
get_class($foo),
class_parents(Foo::class)
);
Note This probably makes most sense if both classes FooUsingBarTrait and FooNotUsingBarTrait implement a common interface - after all, you probably want to provide some functionality which will be shared between the two implementations: one using a trait, the other by other means (methods provided by that class).
For reference, see:
http://php.net/manual/en/function.class-parents.php
http://php.net/manual/en/function.trait-exists.php
For examples, see:
https://3v4l.org/fCLkt
https://3v4l.org/f77cn
no matter how bad it is, you can do it by extending the class.
trait AutoPilot {
function navigate() {
echo 'navigating...';
}
}
if (trait_exists('AutoPilot')) {
class Machine {
use AutoPilot;
}
} else {
class Machine {
}
}
class Car extends Machine {
}
$car = new Car;
$car->navigate();
Your question is fun, and eval() likely meets your needs. This style using code generation is ugly, but I know it works because I verified it myself on my own machine. Here's how you can do it:
$src = '
class foo {
var $bar; // and all of your other code goes here
';
if (file_exists('myTrait.php')) {
include_once('myTrait.php');
$src .= "use myTrait;\n";
}
$src .= "}";
eval ($src); // your class finally gets declared
I don't use eval() often, but it's fun when it solves a problem that otherwise cannot be conventionally solved.
Here what i've ended up with :
eval("class myClass {"
. (trait_exists('myTrait') ? "use myTrait;" : "")
. str_replace(['class ', '<?php'], '//', file_get_contents(myClass.php"))
);
Total lazyness:
Duplicate trait_exists line to add more traits
Comments out the class keyword and the <?php tag so you don't have to edit the class file
evaluates the one long line of smelly code.
This works just fine for me and 'as is' without any modification to any file except the one i paste this line in. It will probably won't be the case for you.
Consider the fact that:
don't use closing php tag
only one class by file
you need to add any other keywords (extends, implements,...)
and probably way more unexpected behaviour depending on your code
Thanks to lacalheinz for his instructive post but Steven aimed at the bulleyes with eval().

use class from namespace in php in class method

I'm new to php and trying to use namespaces for the first time and I have this crazy problem in a big php file (simplified below):
B.php:
namespace Logic;
class C {}
class B {}
A.php:
use Logic\C;
class A extends \BaseClass {
public function __construct() {}
// [...500 lines of code...]
private function hi() { $c = new C(); }
}
The hi method gives the error: Class 'Logic\\C' not found in A.php
But if I just reference B in the constructor of A, it works as expected:
class A extends \Base {
public function __construct() { $dummy = new C(); }
// [...500 lines of code...]
private function hi() { $c = new C(); }
}
When the hi method in the modified code above is run, there are no problems.
Can anybody think of a reasonable explanation for why this happens? Am I misusing namespaces in php?
You need to understand, that the use statement doesn't automatically include the source code file where Logic\C is defined. You need to use an autoloader, or manually require_once that file before accessing classes from that file.
I suggest to follow the manual about namespaces (and the examples there): http://php.net/manual/en/language.namespaces.php

PHP parent and using it in code not in the class itself?

I have 2 classes like
class A {
public function B () {
return 'b';
}
}
class C extends A {
public function D () {
return 'd';
}
}
I know that to use function b in class C I do,
class A {
public function B () {
return 'b';
}
}
class C extends A {
public function D () {
$b = parent::B();
return 'd';
}
}
But what about when I initiate the object? Do I have to do (which works)
$c = new C();
$b = $c -> b();
Or do I still have to use this parent keyword?
I tried doing,
$c = new C();
$b = $c -> parent::B();
But it does not work.
Thanks
You do not need the parent keyword in the second example, since class C extends A, it inherits all of its member functions and variables. So, $c->b(); is perfectly valid. Here is a link to the documentation on the extends keyword, which states:
Often you need classes with similar variables and functions to another
existing class. In fact, it is good practice to define a generic class
which can be used in all your projects and adapt this class for the
needs of each of your specific projects. To facilitate this, classes
can be extensions of other classes. The extended or derived class has
all variables and functions of the base class (this is called
'inheritance' despite the fact that nobody died) and what you add in
the extended definition.
When class C extends from A, you can use this to reach function B():
class C extends A {
public function D () {
$b = $this->B();
return 'd';
}
}
And likewise, from an instantiated class C you should call it as you mentioned using $c->B(). The parent:: construct is only meant to be used inside class methods; it can't be used outside of the class declaration.
Use the one that works.
When an instance inherits functions they are directly callable from that object. The caller does not need to be aware of whether b is some function of C or if c inherited it from another class.

Can I extend a class using more than 1 class in PHP?

If I have several classes with functions that I need but want to store separately for organisation, can I extend a class to have both?
i.e. class a extends b extends c
edit: I know how to extend classes one at a time, but I'm looking for a method to instantly extend a class using multiple base classes - AFAIK you can't do this in PHP but there should be ways around it without resorting to class c extends b, class b extends a
If you really want to fake multiple inheritance in PHP 5.3, you can use the magic function __call().
This is ugly though it works from class A user's point of view :
class B {
public function method_from_b($s) {
echo $s;
}
}
class C {
public function method_from_c($s) {
echo $s;
}
}
class A extends B
{
private $c;
public function __construct()
{
$this->c = new C;
}
// fake "extends C" using magic function
public function __call($method, $args)
{
$this->c->$method($args[0]);
}
}
$a = new A;
$a->method_from_b("abc");
$a->method_from_c("def");
Prints "abcdef"
You cannot have a class that extends two base classes. You could not have the following:
// this is NOT allowed (for all you google speeders)
Matron extends Nurse, HumanEntity
You could however have a hierarchy as follows...
Matron extends Nurse
Consultant extends Doctor
Nurse extends HumanEntity
Doctor extends HumanEntity
HumanEntity extends DatabaseTable
DatabaseTable extends AbstractTable
and so on.
You could use traits, which, hopefully, will be available from PHP 5.4.
Traits is a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way, which reduces complexity and avoids the typical problems associated with multiple inheritance and Mixins.
They are recognized for their potential in supporting better composition and reuse, hence their integration in newer versions of languages such as Perl 6, Squeak, Scala, Slate and Fortress. Traits have also been ported to Java and C#.
More information: https://wiki.php.net/rfc/traits
Classes are not meant to be just collections of methods. A class is supposed to represent an abstract concept, with both state (fields) and behaviour (methods) which changes the state. Using inheritance just to get some desired behaviour sounds like bad OO design, and exactly the reason why many languages disallow multiple inheritance: in order to prevent "spaghetti inheritance", i.e. extending 3 classes because each has a method you need, and ending up with a class that inherits 100 method and 20 fields, yet only ever uses 5 of them.
There are plans for adding mix-ins soon, I believe.
But until then, go with the accepted answer. You can abstract that out a bit to make an "extendable" class:
class Extendable{
private $extender=array();
public function addExtender(Extender $obj){
$this->extenders[] = $obj;
$obj->setExtendee($this);
}
public function __call($name, $params){
foreach($this->extenders as $extender){
//do reflection to see if extender has this method with this argument count
if (method_exists($extender, $name)){
return call_user_func_array(array($extender, $name), $params);
}
}
}
}
$foo = new Extendable();
$foo->addExtender(new OtherClass());
$foo->other_class_method();
Note that in this model "OtherClass" gets to 'know' about $foo. OtherClass needs to have a public function called "setExtendee" to set up this relationship. Then, if it's methods are invoked from $foo, it can access $foo internally. It will not, however, get access to any private/protected methods/variables like a real extended class would.
Use traits as base classes. Then use them in a parent class. Extend it .
trait business{
function sell(){
}
function buy(){
}
function collectMoney(){
}
}
trait human{
function think(){
}
function speak(){
}
}
class BusinessPerson{
use business;
use human;
// If you have more traits bring more
}
class BusinessWoman extends BusinessPerson{
function getPregnant(){
}
}
$bw = new BusinessWoman();
$bw ->speak();
$bw->getPregnant();
See now business woman logically inherited business and human both;
EDIT: 2020 PHP 5.4+ and 7+
As of PHP 5.4.0 there are "Traits" - you can use more traits in one class, so the final deciding point would be whether you want really an inheritance or you just need some "feature"(trait). Trait is, vaguely said, an already implemented interface that is meant to be just used.
Currently accepted answer by #Franck will work but it is not in fact multiple inheritance but a child instance of class defined out of scope, also there is the `__call()` shorthand - consider using just `$this->childInstance->method(args)` anywhere you need ExternalClass class method in "extended" class.
Exact answer
No you can't, respectively, not really, as manual of extends keyword says:
An extended class is always dependent on a single base class, that is,
multiple inheritance is not supported.
Real answer
However as #adam suggested correctly this does NOT forbids you to use multiple hierarchal inheritance.
You CAN extend one class, with another and another with another and so on...
So pretty simple example on this would be:
class firstInheritance{}
class secondInheritance extends firstInheritance{}
class someFinalClass extends secondInheritance{}
//...and so on...
Important note
As you might have noticed, you can only do multiple(2+) intehritance by hierarchy if you have control over all classes included in the process - that means, you can't apply this solution e.g. with built-in classes or with classes you simply can't edit - if you want to do that, you are left with the #Franck solution - child instances.
...And finally example with some output:
class A{
function a_hi(){
echo "I am a of A".PHP_EOL."<br>".PHP_EOL;
}
}
class B extends A{
function b_hi(){
echo "I am b of B".PHP_EOL."<br>".PHP_EOL;
}
}
class C extends B{
function c_hi(){
echo "I am c of C".PHP_EOL."<br>".PHP_EOL;
}
}
$myTestInstance = new C();
$myTestInstance->a_hi();
$myTestInstance->b_hi();
$myTestInstance->c_hi();
Which outputs
I am a of A
I am b of B
I am c of C
<?php
// what if we want to extend more than one class?
abstract class ExtensionBridge
{
// array containing all the extended classes
private $_exts = array();
public $_this;
function __construct() {$_this = $this;}
public function addExt($object)
{
$this->_exts[]=$object;
}
public function __get($varname)
{
foreach($this->_exts as $ext)
{
if(property_exists($ext,$varname))
return $ext->$varname;
}
}
public function __call($method,$args)
{
foreach($this->_exts as $ext)
{
if(method_exists($ext,$method))
return call_user_method_array($method,$ext,$args);
}
throw new Exception("This Method {$method} doesn't exists");
}
}
class Ext1
{
private $name="";
private $id="";
public function setID($id){$this->id = $id;}
public function setName($name){$this->name = $name;}
public function getID(){return $this->id;}
public function getName(){return $this->name;}
}
class Ext2
{
private $address="";
private $country="";
public function setAddress($address){$this->address = $address;}
public function setCountry($country){$this->country = $country;}
public function getAddress(){return $this->address;}
public function getCountry(){return $this->country;}
}
class Extender extends ExtensionBridge
{
function __construct()
{
parent::addExt(new Ext1());
parent::addExt(new Ext2());
}
public function __toString()
{
return $this->getName().', from: '.$this->getCountry();
}
}
$o = new Extender();
$o->setName("Mahdi");
$o->setCountry("Al-Ahwaz");
echo $o;
?>
I have read several articles discouraging inheritance in projects (as opposed to libraries/frameworks), and encouraging to program agaisnt interfaces, no against implementations.
They also advocate OO by composition: if you need the functions in class a and b, make c having members/fields of this type:
class C
{
private $a, $b;
public function __construct($x, $y)
{
$this->a = new A(42, $x);
$this->b = new B($y);
}
protected function DoSomething()
{
$this->a->Act();
$this->b->Do();
}
}
Multiple inheritance seems to work at the interface level.
I made a test on php 5.6.1.
Here is a working code:
<?php
interface Animal
{
public function sayHello();
}
interface HairyThing
{
public function plush();
}
interface Dog extends Animal, HairyThing
{
public function bark();
}
class Puppy implements Dog
{
public function bark()
{
echo "ouaf";
}
public function sayHello()
{
echo "hello";
}
public function plush()
{
echo "plush";
}
}
echo PHP_VERSION; // 5.6.1
$o = new Puppy();
$o->bark();
$o->plush();
$o->sayHello(); // displays: 5.6.16ouafplushhello
I didn't think that was possible, but I stumbled upon in the SwiftMailer source code, in the Swift_Transport_IoBuffer class, which has the following definition:
interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream
I didn't play with it yet, but I thought it might be interesting to share.
I just solved my "multiple inheritance" problem with:
class Session {
public $username;
}
class MyServiceResponsetype {
protected $only_avaliable_in_response;
}
class SessionResponse extends MyServiceResponsetype {
/** has shared $only_avaliable_in_response */
public $session;
public function __construct(Session $session) {
$this->session = $session;
}
}
This way I have the power to manipulate session inside a SessionResponse which extends MyServiceResponsetype still being able to handle Session by itself.
If you want to check if a function is public see this topic : https://stackoverflow.com/a/4160928/2226755
And use call_user_func_array(...) method for many or not arguments.
Like this :
class B {
public function method_from_b($s) {
echo $s;
}
}
class C {
public function method_from_c($l, $l1, $l2) {
echo $l.$l1.$l2;
}
}
class A extends B {
private $c;
public function __construct() {
$this->c = new C;
}
public function __call($method, $args) {
if (method_exists($this->c, $method)) {
$reflection = new ReflectionMethod($this->c, $method);
if (!$reflection->isPublic()) {
throw new RuntimeException("Call to not public method ".get_class($this)."::$method()");
}
return call_user_func_array(array($this->c, $method), $args);
} else {
throw new RuntimeException("Call to undefined method ".get_class($this)."::$method()");
}
}
}
$a = new A;
$a->method_from_b("abc");
$a->method_from_c("d", "e", "f");
You are able to do that using Traits in PHP which announced as of PHP 5.4
Here is a quick tutorial for you, http://culttt.com/2014/06/25/php-traits/
One of the problems of PHP as a programming language is the fact that you can only have single inheritance. This means a class can only inherit from one other class.
However, a lot of the time it would be beneficial to inherit from multiple classes. For example, it might be desirable to inherit methods from a couple of different classes in order to prevent code duplication.
This problem can lead to class that has a long family history of inheritance which often does not make sense.
In PHP 5.4 a new feature of the language was added known as Traits. A Trait is kind of like a Mixin in that it allows you to mix Trait classes into an existing class. This means you can reduce code duplication and get the benefits whilst avoiding the problems of multiple inheritance.
Traits
PHP does not yet support multiple class inheritance, it does however support multiple interface inheritance.
See http://www.hudzilla.org/php/6_17_0.php for some examples.
PHP does not allow multiple inheritance, but you can do with implementing multiple interfaces. If the implementation is "heavy", provide skeletal implementation for each interface in a seperate class. Then, you can delegate all interface class to these skeletal implementations via object containment.
Always good idea is to make parent class, with functions ... i.e. add this all functionality to parent.
And "move" all classes that use this hierarchically down. I need - rewrite functions, which are specific.
class A extends B {}
class B extends C {}
Then A has extended both B and C

Categories