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
Related
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();
}
}
I have written two class at two different file, for example file classA.php and classB.php, the file written below.
file classA.php
class a {
public function __construct() {
require_once('classB.php');
$classB = new b();
}
}
$classA = new a();
file classB.php
class b {
public function __construct() {
echo "Hello World!";
}
}
And the code work fine, and output Hello World! as well. But when I write both of the class like this
class a {
public function __construct() {
class b {
public function __construct() {
echo "Hello World!";
}
}
$classB = new b();
}
}
$classA = new a();
It showing an error
Fatal error: Class declarations may not be nested
Which i think both of them should be do the same thing, yesterday i found something about "arbitrary places" but i don't find the correct answer for what it is.
I just want to know why both of them, showing different result? or maybe something about include or require that i didn't know?
NOTE
I'm not asking what the different between require() and include() functions
Your answer is in the PHP documentation:
When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.
So, unlike for variables, it doesn't matter where the require_once line is: the class will always be at the global scope.
Note that even the namespace of the including file is not applied to the included file, so the included functions and classes are not just in the global scope but also the root namespace.
You are not allowed to define a class within the definition of another class (unless using the new anonymous class features I'm guessing).
You can define multiple classes within the same file but not one class within the code of another class.
If using Composer to generate classmap based autoloading it will correctly work with multiple classes defined in 1 file.
class a {
public function __construct() {
require_once('classB.php');
$classB = new b();
}
}
$classA = new a();
Is not same as
class a {
public function __construct() {
class b {
public function __construct() {
echo "Hello World!";
}
}
$classB = new b();
}
}
This willl also work:
require_once('classB.php');
class a {
public function __construct() {
$classB = new b();
}
}
$classA = new a();
if you use include() or require(). That means You can use their properties like variable,methos,etc.
Example: You have vars.php file
<?php
$color='red';
$car='BMW';
?>
THen You can use $color and $car in html like this :
<h1>Welcome to my home page!</h1>
<?php include 'vars.php';
echo "I have a $color $car.";
?>
class is something like properties. You can use by creating instance of that.
You will get more idea from source
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().
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.
I am a newbie in php oop. My question is is it wise to create object/instance of class in the same class file? like this:
myclass.php
<?php
class myClass{
public $a
function myFunction()
echo $this->a;
}
}
$obj= new myClass;
$obj->$a='This is my class file';
?>
Probably this is wellknown to all expert of php but this is very new and basic concept for me.
There's no rule preventing instantiation of the class in the same file it was defined. It all comes down to what exactly you want to do with it.
For example, you could have a static method that instantiates the class and returns the instance. This is useful for implementing the singleton pattern or the factory pattern. It is however considered bad practice to have global variables like the variable $obj you're defining in your example.
If all you want to do is initialize the instance as it's being created, then you should do so in the constructor.
For example, the MyClass class could reside in a MyClass.php file:
<?php
class MyClass {
private $a;
public function __construct() {
$this->a = 'This is my class file';
}
public function myFunction() {
return $this->a;
}
}
Then, in the file you actually want to use a MyClass instance, you could do something like this:
<?php
require_once 'MyClass.php';
$myInstance = new MyClass();
echo $myInstance->myFunction();