Difference between $bundle and bundle()
bundle is the property on the object. It's where the value is stored. Properties can be assigned one of three ways:


public: these properties can be directly set or read on the object. Example:

$object-&gt;key = 'value';
$value = $object-&gt;key;

private: These can only be accessed by methods (functions) of the class itself. Nothing else can access it. For example, this will throw an error:

$value = $object-&gt;key;


Whereas this would be allowed:

class Example {
  private $key;

  function getPrivateValue() {
    return $this-&gt;key;
  }
}

$value = $object-&gt;getPrivateValue();


$key cannot be accessed outside of the class, since it is private. This can be used to enforce rules on the types of data to be stored in the property. Checks can be run to ensure it's an allowed data type.
protected: These are like private properties, however if a class extends the class, the extended class can access the property. If the property is private, extended classes cannot access it.


One thing for you to understand is that $node-&gt;bundle and $node-&gt;bundle() are not the same things. The first is a property, the other is a method. This should help understand, as a (non-real) example:

class Node {
  protected $bundle;

  public function bundle() {
    return $this-&gt;bundle;
  }
}


The above class has the property $bundle, and the method (function) bundle(). The method returns the value stored in the property.

Look at the error you are seeing: Cannot access protected property Drupal\field\Entity\FieldConfig::$bundle. This is because you are trying to access the $bundle property, but it is protected, meaning you cannot access it from outside the class.

To get the bundle of a node, you need to call the bundle() method on it, which will give you the bundle type. This is the answer to your question about which to use.


  And in a more general point of view, are there some guidelines when to  use functions and when to use variables?


It's generally thought to be a best practice to not provide direct access to properties on objects, and instead create setter and getter methods (functions) on objects to set and retrieve the property values. That way you can say, enforce a pattern:

class Example {

  protected $username

  public function setUsername($username) {
    if (!is_string($username)) {
      throw new \Exception('Username must be a string');
    }
    elseif (!preg_match('/^[a-zA-Z0-9_-]{3,12}$/', $username)) {
      throw new \Exception('Username must be between 3 and 12 characters, and may contain only alphanumerics, underscores or hyphens');
    }

    $this-&gt;username = $username;
  }

  public function getUsername() {
    return $this-&gt;username;
  }
}


The above enforces that username is both a string, and is the right length and only contains allowed characters.

Edit: Additional comment from Leigh:

another reason to avoid accessing the property directly is when you have multiple values. e.g. if you have a field "my_field" on a node which has multiple values if you use $node->my_field->value you'll only get 1 value returned