Namespaces interfering with Classes in PHP - Best Practices? [duplicate] - php

I am trying the following :
//file1.
namespace foo;
class mine {
public function mine() {
echo "Does not work!!";
}
}
//file2.
use foo/mine;
include "foo/mine.php";
$obj = new mine();
the above scenario is not working. No errors including the file -- constructor does not get called.
However when i use __constructor(), everything works fine. I am using php v5.4

From php manual:
For backwards compatibility, if PHP 5 cannot find a __construct()
function for a given class, and the class did not inherit one from a
parent class, it will search for the old-style constructor function,
by the name of the class. Effectively, it means that the only case
that would have compatibility issues is if the class had a method
named __construct() which was used for different semantics.
As of PHP 5.3.3, methods with the same name as the last element of a
namespaced class name will no longer be treated as constructor. This
change doesn't affect non-namespaced classes.
You can use the name of the class as constructor (unless the class is namespaced) because PHP5 keeps this for backwards compatibility with PHP4, but this is not recomended because it is the old way and may be removed in newer versions of php. So unless you are writting something that needs for some reason to be PHP4 compatible use __construct().

Below are 2 different possible solutions to the namespace\constructor problem
//parentclass.php
class parentclass
{
public function __construct()
{
//by default, strip the namespace from class name
//then attempt to call the constructor
call_user_func_array([$this,end(explode("\\",get_class($this)))],func_get_args());
}
}
//foo/bar.php
namespace foo;
class bar extends \parentclass
{
public function bar($qaz,$wsx)
{
//...
}
}
$abc = new foo\bar(1,2);
and
//parentclass.php
class parentclass
{
public function __construct()
{
//by default, replace the namespace separator (\) with an underscore (_)
//then attempt to call the constructor
call_user_func_array([$this,preg_replace("/\\/","_",get_class($this))],func_get_args());
}
}
//foo/bar.php
namespace foo;
class bar extends \parentclass
{
public function foo_bar($qaz,$wsx)
{
//...
}
}
$abc = new foo\bar(1,2);

Related

interface declaration in PHP - why do declarations get mixed?

I'm tring to declare interfaces for my classes like this:
namespace Helpers\Interfaces {
interface Cache {
public static function getInstance($profile = null);
}
}
And then I apply them like this:
namespace Helpers {
class Cache implements Interfaces\Cache {
public static function getInstance($profile = null) {
/* ... */
}
}
}
So far, so good (apparently, at least). The problem I have is NetBeans gives me an error stating my class is not abstract and doesn't implement a certain method.
The method belongs to an object I created to gather the configuration parameters needed to operate certain methods without providing specific configuration options depending on the object (like host, port, API key, etc.).
This method is, in this example, called as \Configuration\Helpers\Cache::getConfiguration($profile);
The conflicting declaration comes from this interface:
namespace Configuration\Helpers\Interfaces {
interface Cache {
public static function getConfiguration($profile = null);
}
}
Which is applied as follows:
namespace Configuration\Helpers {
class Cache implements Interfaces\Cache {
public static function getConfiguration($profile = null) {
/* ... */
}
}
}
It's effectively mixing the interfaces, although they're namespaced!
Something I would like to note is both the interface and the class declaration implementing such interface are always in the same file, one file per object.
PHP version is 7.0.13 on NetBeans 8.2.
What am I doing wrong?
Your interfaces and classes are in different namespaces. You may need to add a use statement to your class. For example you can add: use Helpers\Interfaces as Interfaces. This line can go above the class definition: class Cache implements Interfaces\Cache.
See also: http://php.net/manual/en/language.namespaces.definitionmultiple.php

PHP Trait colliding constructor

Apologies if this is a duplicate, I did search for the answer previously.
I'm struggling to overload a method defined in a trait. It throws a fatal error:
Fatal error: Configuration has colliding constructor definitions coming from traits in Configuration.php on line 18
Their Class
<?php
namespace Theirs\Package;
use Theirs\TheirTrait;
class Configration
{
use TheirTrait;
}
My Class
<?php
namespace My\Package;
use Theirs\Package\Configuration as BaseConfiguration;
use My\Trait\MyTrait;
class Configuration extends BaseConfiguration
{
use MyTrait;
}
My Trait
use Theirs\TheirTrait as BaseSomeTrait;
trait MyTrait
{
use BaseSomeTrait;
protected function someMethod($something)
{
// ...
}
}
you can resolve the constructor collision like this.
trait MyTrait {
use BaseSomeTrait{
BaseSomeTrait::__construct as private __otherConstruct;
}
public function __construct(/* maybe params here*/)
{
// maybe other code
$this->__otherConstruct(/* maybe params here*/);
// maybe other code
}
}
if MyClass has a constructor as well you need to do it there additionally, or maybe only there if MyTrait has no constructor...
It looks like both Theirs\TheirTrait\Configration and Theirs\Package\Configuration have a constructor, and the constructor signatures are incompatible. (But without the code of both, it’s hard to tell.)
If Theirs\Package\Configuration is really intended to be used with Theirs\TheirTrait\Configration, you should write them a bug report. Otherwise, I guess there should be some documentation on how to use the class and the trait in your code so that they don’t produce errors.

How to access class members in traits (or get a similar behaviour)?

This is a follow-up to my previous question about resolving the diamond issue in php.
As I state in that question, I resolve my problem by using traits and passing the instance of the class to the method of the trait. Such as:
trait SecurityTrait
{
public function beforeExecuteRouteTrait($controller, Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
return $this->beforeExecuteRouteTrait($this, $dispatcher);
}
}
However, I am still uncomfortable with this as I don't think this is how traits are really supposed to be used. In my reading I haven't found any way in which to access class members in traits (make $this inside a trait refer to the class using it). Is this possible? Or is there another way to implement a similar behaviour?
After reading some of the answers...
Previously I thought I had received errors when using $this->... inside the trait and this led me to believe the trait could not access anything to do with the underlying class. After reading the answers I tried altering my code to use $this->... inside a trait again and it works - which means a typo several weeks ago has given me far too much headache...
The example given previously now looks like this
trait SecurityTrait
{
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
}
Much cleaner and more easily understandable but provides the same functionality.
If you use a trait inside a class then that trait has full access to all class's members and vice versa - you can call private trait methods from the class itself.
Think of traits as code that literally gets copy/pasted into the class body.
For example:
trait Helper
{
public function getName()
{
return $this->name;
}
private function getClassName()
{
return get_class($this);
}
}
class Example
{
use Helper;
private $name = 'example';
public function callPrivateMethod()
{
// call a private method on a trait
return $this->getClassName();
}
}
$e = new Example();
print $e->getName(); // results in "example"
print $e->callPrivateMethod(); // results in "Example"
In my view referencing classes in traits is not the best way to use them but there's nothing stopping anyone from doing it.
No, that's exactly what Traits are for. Your class already extends a class so you can't inherit the methods and variables of any other classes.
Think of a Trait like copy/paste for code execution. When a class includes a Trait, it's just as if you had written all that code into the class itself.

Conditional Declaring of Extending Class (Overwriting) Method, Based on the Parent Method's Default Parameters

I am creating a plugin for a CMS that provides a few base classes (let's say one of these classes is called Base). This class has a few helper methods that must be overwritten in the extending class. We should note that the base methods have default parameters/values provided. In one version of the LMS these values are provided by reference in the next version just by value.
For example (CMS v1.0):
function prepareTable(&$table){...
CMS v1.1:
function prepareTable($table){...
When you extend the Base class and overwrite the prepareTable method you have to declare it with the same default parameters/values as well, otherwise a STRICT PHP warning is displayed (on by default in PHP 5.4).
My question is, how do I conditionally overwrite the method from the parent class in a working way, knowing the version of the parent CMS?
Here's what I have currently (not working at the moment):
class Base{
function prepareTable(&$table){
}
}
class Extending extends Base{
if(CMS_VERSION=='1.0')
function prepareTable(&$table){
else
function prepareTable($table){
echo $table;
}
}
Obviously, I can not edit the Base and its method directly.
EDIT: Here's the exact error message:
Strict standards: Declaration of Extending::prepareTable() should be compatible with Base::prepareTable($table) in.
the only way I can think of achieving this without duplicating the code inside prepareTable is to create a pseudo function that gets called inside prepareTable and then declare that in the final extended class
if(CMS_VERSION=='1.0') {
class Base2 extends Base{
function prepareTable(&$table){
return $this->prepareTable2($table);
}
function prepareTable2(&$table){
}
}
} else {
class Base2 extends Base{
function prepareTable($table){
return $this->prepareTable2($table);
}
function prepareTable2(&$table){
}
}
}
class Extending extends Base2{
function prepareTable2(&$table){
echo $table;
}
}
if(CMS_VERSION=='1.0') {
class Extending extends Base{
function prepareTable(&$table){
}
}
} else {
class Extending extends Base{
function prepareTable($table){
}
}
}
Note that the if/else check must be done before the class is defined, not inside the class. Essentially, you are building two different versions of the class.
Side Note: If you need to include shared methods, that won't be changed between the two versions of the class, you can define a new class that will extend Extending, create the shared methods there and use this new class.
For example (place this after the code above):
class ExtendingFull extends Extending{
// Here you may include your shared methods
// e.g:
public function sharedMethod(){
echo 'test';
}
}

PHP Class Extensions

I was just wondering if the next situation could be possible or not, I've read the PHP Manual documentation, but I would like another perspective because it's not so clear for me.
So I have for example one class:
class SomeClass {
public function someFunction() {
...
}
}
And an extension of it:
class Extension extends SomeClass {
public function someOtherFunction() {
...
}
}
My question is, could I be able to use the public functions inside the classes on both ways, the main class's function inside the extended function and the other way around?
And would I be doing that how?
You can use both functions from class Extension, but only someFunction() from class SomeClass.
Extension does not change the original class, it just incorporates it into a new one.
You can use the public and protectedfunctions of your parent in the extended (child) class:
class Extension extends SomeClass
{
public function someOtherFunction() {
$foo = $this->someFunction(); // from parent class
return $foo;
}
}
When class "Extension" is created, its basically a copy of "SomeClass" which you can modify in the way as you can add new functions or overwrite those of the parent class.
The parent does not know about the Extension (it can be extended multiple times, eg "JSONRequest extends Request", "XMLRequest extends Request"). Calling extended functions from within the parent makes no sense, since the parent class can never know which childs function it should call in such a situation. This type of Inheritance is one of the basic concepts of OOP and clear interfaces.
In other words, no it will never work the other way round. And it should not.

Categories