I know, that are some stupid questions, but I am a little bit confused.
Above, it is a screenshoot from https://docs.typo3.org/m/typo3/book-extbasefluid/main/en-us/7-Controllers/1-Creating-Controllers-and-Actions.html.
As you can see, in one case there is no '\' before MyVendor, in another one it is. Are both way possible?
In my extensions I have under Classes the following structure.
If I use the use function, It is not necessary to `Classes in the statement.
use MyVendor\ExtName\Controller\MainController is enough?
You are use'ing namespace, not file structure, so you must use exact namespace
If you want to use methods from class, you must use that class. If function (not method) is under namespace, then that function must be used (as there is no class to use)
Leading \ is optional, but preferred style is without leading \
// a.php
namespace MyVendor\ExtName\Controller;
function test() {
echo 'Test2';
}
class MainController {
public static function test() {
echo 'Test';
}
}
// b.php
namespace AnotherVendor\ExtName\Controller;
class MainController {
public static function test() {
echo 'Test 3';
}
}
// c.php
namespace MyVendor\ExtName\Utilities;
use MyVendor\ExtName\Controller\MainController;
use AnotherVendor\ExtName\Controller\MainController as AnotherController;
use function MyVendor\ExtName\Controller\test;
class MainUtility {
public function foo() {
MainController::test();
AnotherController::test();
test();
}
}
Related
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().
I want a base class to be extended, but I have some errors coming out:
Fatal error: Class 'Api\Services\Base' not found in
/var/www/html/Api/Services/Example.php on line 7
I searched for typos, tried to use the fully qualified name, made the abstract class empty or just defined it as a simple class; none of these helped.
Using "require" instead of "use" worked, but still...
Any idea (the two files are in the same directory: /var/www/html/Api/Services)?
Thanks in advance...
<?php
// Base.php
namespace Api\Services;
use Api\Classes\ErrorHandler;
use Api\Classes\ErrorMessage;
abstract class Base
{
public $data = null;
public function getData()
{
return $this->data;
}
public function setData($data = null)
{
$this->data = $data;
}
}
?>
<?php
// Example.php
namespace Api\Services;
use Api\Services\Base;
class Example extends Base
{
public $request = array();
public function __construct($request = array())
{
$this->request = $request;
}
}
?>
use Base
instead of
use Api\Services\Base;
because you are already inside the namespace Api\Services
Actually, you don't even have to write the use statement, you are inside the namespace, you can just call the classes inside the same namespace without including them (use)
Decided to start using namespaces in my PHP projects and am struggling in getting this simple setup to work... What am I doing wrong?
First.php
<?php
namespace MyNamespace;
use PDO;
class First {
function hello() {
return 'hello';
}
}
Second.php
<?php
namespace MyNamespace;
use PDO;
use function \MyNamespace\First;
class Second {
function world() {
$firstpart = \MyNamespace\First::hello();
return $firstpart . ' world';
}
}
index.php
<?php
echo \MyNamespace\Second::world();
?>
This gives me an error:
Strict Standards: Non-static method MyNamespace\Second::world() should not be called statically in /var/www/testsite/index.php on line 2
Basically, I am looking for a way to call different functions in different classes within the same namespace. Have never used namespaces before and for the life of me however I try to call my functions, they end up giving me the same errors. Any pointers please?
Your error indicates an attempt to call a static method, which is not (class Second, method world - not static)
And importing function space names must be as follows:
First.php
<?php
namespace MyNamespace;
function hello() {
return 'hello';
}
Second.php
<?php
namespace MyNamespace;
use function \MyNamespace\First\hello;
class Second {
static function world() {
$firstpart = hello();
return $firstpart . ' world';
}
}
And use, for example:
Second::world()
(I add static word in declaration method world)
Read this
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
class Second
{
// i've got to access to $variable from First instance from here
}
class First
{
public $variable;
public $SecondInstance;
public function __construct($variable)
{
$this->variable = $variable;
$this->SecondInstance = new Second();
}
}
$FirstObj = new First('example variable');
I need an equivalent for parent::$variable for objects.
Is there a possibility to do that in that way?
No, you cannot. The only way you can manage that, without extending First, is to pass "$this" to the constructor of Second:
$this->SecondInstance = new Second ($this);
Or, you can simply pass $variable to its constructor.
You mean like the parent function in PHP:
//You may find yourself writing code that refers to variables
//and functions in base classes. This is particularly true if
// your derived class is a refinement or specialisation of
//code in your base class.
//Instead of using the literal name of the base class in your
//code, you should be using the special name parent, which refers
//to the name of your base class as given in the extends declaration
//of your class. By doing this, you avoid using the name of your base
//class in more than one place. Should your inheritance tree change
//during implementation, the change is easily made by simply
//changing the extends declaration of your class.
<?php
class A {
function example() {
echo "I am A::example() and provide basic functionality.<br />\n";
}
}
class B extends A {
function example() {
echo "I am B::example() and provide additional functionality.<br />\n";
parent::example();
}
}
$b = new B;
// This will call B::example(), which will in turn call A::example().
$b->example();
?>
I would recommend you change your strucutre a little to "extend":
class second extends first{
public __construct(){
parent::__construct();
echo $this->variable;
}
}
Otherwise you will need to assign the "first" as a parent class within the variables on the second and actually access it like that:
class second{
public $first;
public function __construct($first){
$this->first = $first;
var_dump($this->first->variable);
}
}
Or of course you can also make the first class static and access it that way.