March 12, 2013

Concatenating lang CONST and STR CONST in PHP

Question by Jorge

Trying to concatenate:

<?php
class MD_ImpFormularios extends CI_Model {
  private $dir_forms = __DIR__ . 'Hola';

Gives:

PHP Parse error:  syntax error, unexpected '.', expecting ',' or ';' in md_impformularios.php on line 3

But I don’t see anything wrong here, it isn’t a CONST or Static, it’s a simple variable.

Thanks

Answer by Starx

Do not do concatenation while declaring class variables.

private $dir_forms = __DIR__ . 'Hola';
                          // ^ This is NOT allowed during declaration

You can use your constructor function to set such variables.

private $dir_forms;
public function __construct() {
    $this -> dir_forms = __DIR__ . 'Hola';
}
May 6, 2012

PHP OOP how to group configuration data

Question by cl0udw4lk3r

i wanna store some configuration data in some objects, and i’ve a problem…

class B {
  const attr1 = 'something1';
  const attr2 = 'something2';
  const attr3 = 'something3';
}

class A {
  const attr1 = 'somethingA1';
  const attr2 = 'somethingA2';
  const attr3 = 'somethingA3';
  const b = <---- i wanna put here a reference of B, but B as a class (not an object...), i'm crazy?
}

I’m not sure if my example is clear… from A, i want to access to attr1 of B, like A::B::attr1, or something like this, there’s another way to do this? Or i’m wrong?

Answer by Gordon

There is no way to assign reference to a Class, nor is there a way to assign class constants at runtime. So your entire approach is pretty much impossible. What you can do is

const b = 'B' 

and as of PHP 5.3.0 you could then do

$b = A::b;
echo $b::attr1;

but you cannot do A::b::attr1. This will raise a T_PAAMAYIM_NEKUDOTAYIM error. It’s a parser limitation. PHP cannot do this as of this writing.


Because the class B contains a group of data of A, i want to store in b (of A) a complex data, i want to do like this because i wanna keep the code clean

You can solve this easily by making B a composite of A, e.g. you either inject B into A when you create A

class A
{
    private $b;

    public function __construct(B $b)
    {
        $this->b = $b;
    }
}
$a = new A(new B);

or create B inside A, e.g.

class A
{
    private $b;

    public function __construct()
    {
        $this->b = new B;
    }
}

Because B is just the data parts of A, you tunnel all public access through A instead of getting hold of B and then using B’s methods. So any code using A does not need to know there is some B inside A. This will allow you to change B easily without needing to worry about code that consumes A, e.g. to get attr1 you add a getter to A:

public function getAttr1()
{
    $b = $this->b;
    return $b::attr1;
}

You can mitigate the clumsy need for assignment when using properties instead of constants in B (constants are stupid in PHP anyway as you have to treat them as public API), e.g.

class B
{ 
    private $attr1;

    public function getAttr1()
    {
        return $this->attr1;
    }
}

And then you can do in A:

public function getAttr1()
{
    return $this->b->getAttr1();
}

Even better would be not to expose the internals of B through A altogether though and only add public methods that do something with A. This will make your API much smaller and your code more OO.

Answer by Starx

You cannot reference to a class like that, because the only way you will ever use the class is through an object, so there is no point trying to do that either.

User this:

class A {
  const attr1 = 'somethingA1';
  const attr2 = 'somethingA2';
  const attr3 = 'somethingA3';
  public $b;

  function __construct() {
    $this -> b = new b();
}
...

Please fill the form - I will response as fast as I can!