PHP cannot find class file - php

Normaly I would include my class file before I create an object. My question is how I can include a class file only in my main file and then use it method in another class? Here is my code:
main file:
require_once("class.a.php");
require_once("class.b.php");
var $a;
function main () {
$a = new class.a();
$b = new class.b();
}
class b:
class b {
var $a;
function __construct() {
$this->a = class.a::method();
}
}
This seems to work in some older PHP version but it gives an error file class.a.php not found in some new PHP version.
Edit: I've corrected my question: class.b uses direct calls to method from class.a. This gives me an error class.a.php not found. I can fix this error when I add a require_once("class.a.php") to class.b.php like this:
require_once("class.a.php");
class b {
var $a;
function _constructor() {
$this->a = class.a::method();
}
}
But then I have two includes and also this doesn't work with an update version of php?

Well, new class.a() should create a syntax error as . is not a valid operator anywhere apart from string concatenation. You want
class a {
// do something
}
$a = new a();
As to the require_once, well, once you have included or required a file in a PHP script, all of the classes/functions/variables/constants/etc. will continue to persist in all other files which are included after the require. So your problem here is clearly the syntax problem.
Additionally, you may want to consider modifying the following:
var $a; is outdated, it should be public $a (or protected or private). var is still valid because it is backwards-compatible with PHP 4, but it is generally a bad idea.
It is __construct not _constructor
a::method(); means "Call the static method of class a". You want something like $this->a = new a(); $this->a->method();

You should NOT have dots (.) in class names.
And you might want to consider using an autoloader

Change the name of your classes as stated on other answers. Make them as "a" and "b". You have to use dependency injection on class b.
b {
public $a;
function __construct(a $a) {
$this->a = $a; // now you have the instance of class.a in your class.b
}
}
And your main.php
require_once("class.a.php");
require_once("class.a.php");
function main () {
$a = new a()
$b = new b($a);
$b->a->method(); // call the method of a
}

Related

PHP - Two classes, talk to each other correctly

I have a small problem. I've tried searching, but I can't get the search terms quite right and was hoping someone could help.
I have an include on every page in my system that works something like this:
<?PHP
require_once("class.system.php");
require_once("class.mysql.php");
$oMySQL = new MySQL();
$oSystem = new SystemClass();
... ?>
But I have a problem. As you may guess - the MySQL class is a bunch of functions that I use to make MySQL calls easier. This isn't the only example of where I want to use it but it's a good example.
I have functions in the system class I want to be able to reference the MySQL class (And vice versa...).
As an example, I have a function in the system class that will populate a session variable with data from MySQL. The only way I can think of doing this (Which I know is wrong...) is:
class SystemClass {
function PopulateSession(){
global $oMySQL;
if($oMySQL->Select('abc')){
$_SESSION['def']= blahblahblah;
return true;
} else {
return false;
}
}
}
It works, but it means every function I want to use it, I have to use global, which I'm sure is very bad practice. Could someone advise??
Thanks
What you encountered is called composition. A good solution would be to use a dependency injection framework. An easy solution is to roll with constructor parameters.
public class A {
private $b;
public function __construct($b) {
$this->b = $b;
}
}
$b = new B;
$a = new A($b);
Or, as a more flexible solution, when you have mutual dependencies:
public class A {
private $b;
public function setB($b) {
$this->b = $b;
}
}
public class B {
private $a;
public function setA($a) {
$this->a = $a;
}
}
$a = new A;
$b = new B;
$a->setB($b);
$b->setA($a);
But the downside is that as the number of dependencies grows, it's hard to manage and remember to set all the dependencies. This is exactly the reason why Dependency Injection frameworks are popular.

Cannot access class constant from an instance using the :: scope operator

I hit a strange problem today and even as a PHP engineer i'm stumped at this:
It seems you can access a class constant from an object instance such as:
class a {
const abc = 1;
}
$a = new a();
var_dump($a->abc);
This will output null instead of the expected 1. I was able to do the following:
class a {
const abc = 1;
}
$a = new a();
var_dump(a::abc);
But in the context of a sub object that doesn't really know who the parent is exactly, i find it extremely annoying to do:
class a {
const abc = 1;
}
$a = new a();
$c = get_class($a);
var_dump($c::abc);
Is it me or this is completly stupid, if not, please enlighten me why its working that way.
EDIT
Another way of doing it but it's not really better:
class a {
const abc = 1;
}
class b {
public function getA(){
return new a();
}
}
$b = new b();
$c = $b->getA();
var_dump($c::abc);
This last example works more like what i am doing and experiencing...
Just use the instance variable with the scope resolution operator:
$a = new a();
var_dump($a::abc);
This prints 1.
I found a relatively nice and clean way to make my problem easier to live with. Here is the solution i've applied. It is not necessarely the best but for my uses it does exactly what i need.
By creating a magic __get method, i intercept the request for the constant name from and instance point of view and i use a quick reflection to see if that constant exists and return it's value.
This allows me to actually use all in one line a pattern that looks like this:
class a {
const abc = 1;
public function __get($key){
$r = new ReflectionObject($this);
if($r->hasConstant($key)){ return $r->getConstant($key); }
}
}
class b {
public function getA(){
return new a();
}
}
$b = new b();
var_dump($b->getA()->abc);
var_dump($b->getA()->def);
Althought i'd have liked to do:
var_dump($b->getA()::abc);
var_dump($b->getA()::def);
I guess this could be possible later in 5.4+ considering we finaly have array dereferencing, we could probably ask them to add static dereferencing soon.
The PHP documentation indicates that class constants are accessed via SRO (::) rather than ->.
<?php
class MyClass
{
const constant = 'constant value';
function showConstant() {
echo self::constant . "\n";
}
}
echo MyClass::constant . "\n";
ike I mentioned, in php constants are tied to the class definition, they are static by definition and cannot be accessed using the -> operator.
If you really want to use it with your coding paradigm, you can try the reflection class in php5.
class MyClass
{
const A = "I am A";
}
$o = new ReflectionClass( "MyClass" );
echo $o->getconstant("A"); //will print "I am A"
Also, I think the example in your EDIT might not work..I did not run it, but I am not sure if the SRO(::) can be invoked on anything that is not a class reference..
I know this is an old thread, but for people who want to know the best way to do this have a look at the PHP function constant().
With constant() you can simply do this:
$a = new a();
$value = constant(get_class($a)."::abc");
// $value === 1
this has been available since PHP 4, and still works perfectly in PHP 5.5
When trying to use const defined in a class inside a different namespace, the Scope Resolution Operator (::) can be used without problems as stated by the docs prefixing the namespace before the class in which the const was declared with this format:
(<namespace>"\")*<className>::<const>
With the next namespace, class and const definitions:
models/OperationModel.php
<?php
namespace models;
class OperationModel {
const OPERATION_INITIALIZING = 1;
}
You can use the const from another namespace\class like this:
controllers/MobileController.php
<?php
namespace controllers;
use models\OpertionModel;
class MobileController {
private function thingy() {
$operation_status = models\OperationModel::OPERATION_INITIALIZING;
}
}

$this in php is bound dynamically, right?

I'm getting an error that I think is because I've made some kind of mistake in a refactoring, but I can't find documentation on when $this is bound, and my error could be explained by it being bound statically.
Extra points (I can't actually give you extra points) for links to excellent documentation about this kind of thing in php.
[Edit]
The error that I'm getting is telling me that Subclass::$var doesn't exist when I do, for example, echo $this->var in a superclass. The $var exists in the subclass, though.
$this becomes available after you've called the constructor. Logically you can't use $this in a static function.
Aside from calling $this in a static function there isn't a whole lot that can go wrong timing wise as there is simply no way in PHP.
What exactly is the error you're getting? Code would useful too.
This works in PHP:
class A {
public function foo() {
echo $this->bar;
}
}
class B extends A {
public $bar = 1;
}
$b = new B;
$b->foo(); // 1
It works because of the dynamic scope resolution that PHP has (i.e.: scope is resolved at runtime as opposed to compile time). However, I'd recommend against it, because it is really a particularity of the language for one. For second, failing to declare $bar in a subclass would result in an error. I think that a class should only reference members that it is aware of.
The same code, say in C++:
class A {
public:
void foo() {
std::cout << bar;
}
};
class B : public A {
public:
int bar;
B() {
bar = 1;
}
};
...would give you a compile error (In A::foo(): 'bar' was not declared in this scope).
Yes, $this is bound dynamically, as is evidenced by the fact that the output of the following is "foo":
<?php
class Base
{
public function ecc(){
echo $this->subvar;
}
}
class Sub extends Base
{
public $subvar;
public function __construct(){
$this->subvar = 'foo';
$this->ecc();
}
}
new Sub();
?>

PHP5.3: "Call to undefined method" error when calling invoke from class variable

I have been doing some tests (to replace old code) with the __invoke magic method and I'm not sure this is a bug or not:
Lets suppose we have a class:
class Calc {
function __invoke($a,$b){
return $a*$b;
}
}
The following is possible and works without any problem:
$c = new Calc;
$k = $c;
echo $k(4,5); //outputs 20
However if I want to have another class to store an instance of that object,
this doesn't work:
class Test {
public $k;
function __construct() {
$c = new Calc;
$this->k = $c; //Just to show a similar situation than before
// $this-k = new Calc; produces the same error.
}
}
The error occurs when we try to call it like:
$t = new Test;
echo $t->k(4,5); //Error: Call to undefined method Test::k()
I know that a "solution" could be to have a function inside the class Test (named k) to "forward" the call using call_user_func_array but that is not elegant.
I need to keep that instance inside a common class (for design purposes) and be able to call it as function from other classes... any suggestion?
Update:
I found something interesting (at least for my purposes):
If we assign the "class variable" into a local variable it works:
$t = new Test;
$m = $t->k;
echo $m(4,5);
PHP thinks you want to call a method k on instance $t when you do:
$t->k(4, 5)
which is perfectly reasonable. You can use an intermediate variable to call the object:
$b = $t->k;
$b(4, 5);
See also bug #50029, which describes your issue.
When you do $test->k(), PHP thinks you are calling a method on the $test instance. Since there is no method named k(), PHP throws an exception. What you are trying to do is make PHP return the public property k and invoke that, but to do so you have to assign k to a variable first. It's a matter of dereferencing.
You could add the magic __call method to your Test class to check if there is a property with the called method name and invoke that instead though:
public function __call($method, $args) {
if(property_exists($this, $method)) {
$prop = $this->$method;
return $prop();
}
}
I leave adding the arguments to the invocation to you.
You might also want to check if the property is_callable.
But anyway, then you can do
$test->k();
You can not use method syntax (like $foo->bar() ) to call closures or objects with __invoke, since the engine always thinks this is a method call. You could simulate it through __call:
function __call($name, $params) {
if(is_callable($this->$name)) {
call_user_func_array($this->$name, $params);
}
}
but it would not work as-is.
If you call $test->k() PHP will search for a method called "k" on the $test instance and obviously it will throws an Exception.
To resolve this problem you can create a getter of the property "k"
class Test {
public $k;
function __construct() {
$c = new Calc;
$this->k = $c; //Just to show a similar situation than before
// $this-k = new Calc; produces the same error.
}
public function getK() {
return $this->k;
}
}
So now you can use the functor in this way:
$t = new Test();
echo $t->getK()(4,5);

Reference and Overwriting

I have:
class A{
public $name = 'A';
public $B;
public function B_into_A($b)
{
$this->B = $b;
}
}
class B{
public $name = 'B';
public $A;
public function new_A_into_B($a)
{
$this->A = new $a;
}
}
$a = new A;
$b = new B;
$a->B_into_A($b);
$b->new_A_into_B('A');
Is this a good way to insert another class inside a "main" class at the beginning of the runtime?
Should I use references?
(Background: I currently work on a MVC framework in which I have to handle many classes within some main classes e.g. bootstrapper, wrapper, modules, adapter etc.)
Yes and No...
Your first function call was fine, I would just use a more standard name:
$a = new A;
$b = new B;
$a->setB($b); // B_into_A is a little bit of a whacky function name
Your second call, it doesn't really make sense to pass a string and then create the object (Unless you're looking for some sort of factory). If you want B to own A:
$b->new_A_into_B( new A );
public function new_A_into_B($a)
{
$this->A = $a;
}
Again i don't like the name.. Id probably go with setA() there as well.
Passing an object instead of its class name makes sense because then it is easier for the garbage collector to guess when it is not needed anymore.
<?php
class A {
public $B;
}
class B {
public $A;
}
$a = new A;
$b = new B;
$a->B = $a;
$b->A = $b;
Furthermore, I'd try to get rid of the setter methods. In practice the only benefit they provide is to validate input. Since it's not the case here, I'd advise you to directly assign the classes.
You asked "Should I use references?". Actually all objects are passed by reference since PHP5. The only way to get an exact copy of them is to use the clone keyword.
By the way, you do not need to store the class name within each object. Just use get_class().

Categories