0

I want function explicitSetX( $value){} to be public in a specific task otherwise it should be private. (functionality of private)

(Im not interested in how to write generic setters, this question is about Visibility / Accesibility)

class My_Object{

public function genericArrSetter ( $property, $value ){

    $this->$property = $value;
}
}

class Obj extends My_Object{

private $x;
private $x1;
private $x2;
private $x3;
private $x4;
private $x5;
private $x6;
private $x7;
private $x8;

public function explicitSetX( $value){
    $this->XX = $value; 
}

}

/*
* Below functions run from outside
* I would like to force this behaviour since now
* its possible for others to use myStart. (way of setting)
*/

function myStart (){
// set all data in Obj via generic setter
$obj = new Obj();
$obj-> genericArrSetter("x","value for x");
}

function OtherStart (){
// set all data in Obj via explicit setter
$obj = new Obj();
$obj-> explicitSetX ("value for x");
}
  • first: please declare variables with `$`. `private x;` is not correct, use `private $x;`, second: the functions `myStart` and `OtherStart` are in the class `Obj`? – Adrian Preuss Mar 28 '14 at 17:45
  • Perhaps need [some magic](http://www.php.net/manual/en/language.oop5.overloading.php#object.set) –  Mar 28 '14 at 17:56
  • Hopefully Its more understandable now. – user3361120 Mar 28 '14 at 17:57
  • So you want to have `genericArrSetter` function public in `myStart` and private in `OtherStart`? –  Mar 28 '14 at 18:04
  • I want to be able to use a genricArrSetter in one function I have. In all other cases genericArrSetter shouldn't be accessible. – user3361120 Mar 28 '14 at 18:08
  • Why? If the explicit setters are publicly accessible, I don't see how it makes much difference. – WinterMute Mar 28 '14 at 18:12

3 Answers3

1

Why declare your attributes private if you want to access them publicly? In any case, you can use the magic method __set() to write data to private/protected variables

public function __set($name, $value){
    $this->$name = $value;
}

Alternatively you could pass the values into the constructor function:

public function __construct($A, $B, $C){
    $this->A = $A;
    $this->B = $B;
    $this->C = $C;
}

You could use an associative array as the argument instead with a foreach loop:

public function __construct(array $args){
    foreach ($args as $key=>$value){
        $this->$key = $value;
    }
}

The constructor's signature should probably be __construct(array $args=null) so you can use new Obj($args) and new Obj() but you will have to check in the body if $args is not empty.

WinterMute
  • 519
  • 3
  • 9
0

This is hakish and not recommended but you could do something like that:

class My_Object{

    // Final will disallow ovverriding
    public final function genericArrSetter ( $property, $value ){

        // Get caller function name
        $callers = debug_backtrace();

        // If it's not myStart do something more or less nasty
        if($callers[1]['function'] !== 'myStart')
        {
            throw new Exception('This is not allowed');
        }
        $this->$property = $value;
    }
}

Example:

function myStart (){
// set all data in Obj via generic setter
$obj = new Obj();
$obj-> genericArrSetter("x","value for x");
}

function OtherStart (){
// set all data in Obj via explicit setter
$obj = new Obj();
$obj-> explicitSetX ("value for x");
// Below will throw exception
$obj-> genericArrSetter("x","value for x");
}

For more robust solutions for caller name see this: How to get name of calling function/method in PHP?

DISCLAIMER: Not tested not recommended

Community
  • 1
  • 1
  • Ive updated question, think you have another answer now – user3361120 Mar 28 '14 at 18:21
  • This will allow calling `genericArrSetter` (or any way you name it) only from `myStart`, as you written in comment. –  Mar 28 '14 at 18:25
  • Ah yes true, thanks! Though was thinking there would be a more proper OOP to handle this. One solution I'm thinking of is to create a new class that inherits the object and have the generic setter. Then at least its separated and easier to force other developers to use correct way of setting things. – user3361120 Mar 28 '14 at 18:27
  • Well, as a good practice class should be not aware and not dependent of who is calling it. –  Mar 28 '14 at 18:33
0

The only feasible way of doing that is by using interfaces and type hinting.

Declare two interfaces:

interface ExplicitSetter {
    public function setExplicitX($value);
}

interface GenericSetter {
    public function setGeneric($x, $value);
}

Your class implements both.

class MyObject implements ExplicitSetter, GenericSetter {
    private $x;

    public function setExplicitX($value) {
        $this->x = $value;
    }

    public function setGeneric($x, $value) {
        $this->x = $value;
    }

    public function __toString() {
        return $this->x;
    }
}

Now you can use type hinting to only expose the interface you are interested in. Trying to use methods not declared by the interface will result in a error.

function useExplicitSetter(ExplicitSetter $setter) {
    $setter->setExplicitX('Hello explicit');
}

function useGenericSetter(GenericSetter $setter) {
    $setter->setGeneric('x', 'Hello generic');
}

Usage:

$obj = new MyObject();

useExplicitSetter($obj);
echo $obj; // Hello explicit

useGenericSetter($obj);
echo $obj; // Hello generic

http://sandbox.onlinephpfunctions.com/code/a7a7a4c4566b529762d4eea755c11a8a9a8734d4

Bart
  • 17,070
  • 5
  • 61
  • 80