PHP,OOP:为什么我的类的数组属性不能像属于类之外的数组那样使用属性和方法?

So like the title says, I am having a hard time making an array property of one of my classes have it's values be declared as properties & methods.

I can successfully do this if the array is not a property of a class, but as soon as the array is dropped into a class, the script doesn't like those values, and throws me this error.

Fatal error: Constant expression contains invalid operations in C:\xampp\htdocs_webdevepos\mcf\static\inc\classes\class.catalogue.php on line 17

I have both classes being included in a different .php called inc.classes.php. That file is then included in each page. Here is some code to better illustrate my issue,

Master Class File: inc.classes.php

// config
require_once('config/config.php'); // config file

// other tools
require_once(ROOT_DIR . 'inc/parsedown/Parsedown.php'); // tool that I am using for parsing .md files

// my classes
require_once(ROOT_DIR . 'inc/classes/class.vendor.php');
require_once(ROOT_DIR . 'inc/classes/class.catalogue.php');

Class A: class.vendor.php

class Vendor
{
  public $vendor = array(
    'foo' => array(
      'name' => 'Foo Inc.',
      'image' => (VENDOR_IMG . 'foo/foo-logo.png'),
    ),
    'bar' => array(
      'name' => 'Bar Co.',
      'image' => (VENDOR_IMG . 'bar/bar-logo.png'),
    ),
  );

  public function get($data) {
    if (array_key_exists($data, $this->vendors)) {
      return $this->vendors[$data];
    } else {
      // throw error
    }
  }

  // Class methods...
}

Class B: class.catalogue.php

class Catalogue
{
  public $catalogue = array(
    '1' => array(
      $section = $markdown->text(file_get_contents(ROOT_DIR . catalogue/markdown/section1.md')),
      $link = 'catalogue/pdf/section1.pdf,
      $pdf = (ROOT_DIR . $link),
      'title' => 'Section One',
      'content' => mdReplace($section, $pdf, $link),
      'theme' => 'purple',
      'vendors' => array(
        1 => $vendor->get('foo'),
        2 => $vendor->get('bar'),
      ),
    ),
    // '2' ...
  );

  // Class methods...
}

(mdReplace() is a small function located in a seperate php file called inc.functions.php. It's purpose is to replace a few keywords inside of the .md files that contain the sections' content.)

Apologies in advance if I am just blind as a bat right now and am missing something obvious.

If you read php oop manual carefully, here what you will see:

Class member variables are called "properties"... They are defined by using one of the keywords public, protected, or private, followed by a normal variable declaration. This declaration may include an initialization, but this initialization must be a constant value--that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.

See the words

must not depend on run-time information

And your current definition of public $catalogue is dependant of some data that will be evaluated later. That's why you have fatal error.

So, as said the solution is to fill $catalogue data by calling some function - either explicitly or in a __construct for example.

You can't run methods on a class property like that. You'd need to set that up inside your construct:

class Catalogue
{
  public $catalogue = array();

  public function __construct() 
  {
    $this->catalogue = array(
    '1' => array(
      $section = $markdown->text(file_get_contents(ROOT_DIR . catalogue/markdown/section1.md')),
      $link = 'catalogue/pdf/section1.pdf,
      $pdf = (ROOT_DIR . $link),
      'title' => 'Section One',
      'content' => mdReplace($section, $pdf, $link),
      'theme' => 'purple',
      'vendors' => array(
        1 => $vendor->get('foo'),
        2 => $vendor->get('bar'),
      ),
    ),
    // '2' ...
  );
 }
  // Class methods...
}

As Farkie said, you can't run method calls on a class property like the way you did.

The reason is, those objects which you are trying to use are not initialised, and in order for them to work they must be initialised first.

Ex variables which can't directly be used in properly as they are not available to be used

  • $markdown
  • $pdf
  • $section

So for Class B you need to have your code written inside the constructor.

However whatever you have done for Class A is perfectly acceptable and it should work. I could see that you have a typo in the variable name. It should be $vendors as you are trying to refer it inside the function get() as $this->vendors[$data];

The following will work

class Vendor
{
  public $vendors = array(
    'foo' => array(
      'name' => 'Foo Inc.',
      'image' => (VENDOR_IMG . 'foo/foo-logo.png'),
    ),
    'bar' => array(
      'name' => 'Bar Co.',
      'image' => (VENDOR_IMG . 'bar/bar-logo.png'),
    ),
  );

  public function get($data) {
    if (array_key_exists($data, $this->vendors)) {
      return $this->vendors[$data];
    } else {
      // throw error
    }
  }

  // Class methods...
}