Változók láthatósága (scope)

A PowerShellben a változóknak van szabályozható láthatóságuk (scope). Az alapszabály, hogy egy adott környezetben létrehozott változók az alkörnyezetekben is láthatók. Környezet maga a PowerShell konzol, egy függvény, egy script. Ahogy ezeket egymásból meghívjuk generálódnak az al-, al-, … környezetek. A PowerShell konzol az un. „global” környezet, az összes többi, innen hívott függvény vagy szkript ennek alkörnyezete.

Nézzük az egyszerű láthatóság alapesetét:

[1] PS I:\>$a = "valami"

[2] PS I:\>function fv{$a}

[3] PS I:\>fv

valami

[1]-ben létrehoztam egy $a változót, [2]-ben egy nagyon egyszerű függvényt, ami csak annyit csinál, hogy visszaadja $a-t, majd [3]-ban meghívtam ezt az fv nevű függvényt. Az eredmény látható: a függvény „látta” $a-t, ki tudta írni a tartalmát.

Nézzünk egy kicsit bonyolultabb esetet, mi van akkor, ha a függvényemnek is van egy $a változója:

[6] PS I:\>$a = "valami"

[7] PS I:\>function fv1{$a="másvalami";$a}

[8] PS I:\>fv1

másvalami

[9] PS I:\>$a

valami

[7]-ben az fv1 függvényem definiál egy $a-t, majd ki is írja. [8]-ban meg is kaptam a „belső” $a eredményét, de ettől függetlenül [9]-ben a „global” környezetből nézve az $a továbbra is az, ami volt. Azaz a gyerek környezet nem hat vissza a szülőre.

Ha szükségünk van külön a szülő változójára is a függvényen belül, akkor ezt meg tudjuk tenni a get-variable  cmdlet –scope  paraméterének beállításával. A „-scope 0” jelenti a saját környezetet, „-scope 1” jelenti a szülőkörnyezetet, „-scope 2” jelentené a nagyszülőt és így tovább:

[11] PS I:\>function fv2{$a="másvalami";$a; get-variable a -scope 0}

[12] PS I:\>fv2

másvalami

 

Name                           Value

----                           -----

a                              másvalami

[11]-ben a saját $a-t írja ki a get-variable, a következő példában pedig a szülő $a változóját:

[14] PS I:\>function fv2{$a="másvalami";$a; get-variable a -scope 1}

[15] PS I:\>fv2

másvalami

 

Name                           Value

----                           -----

a                              valami

A gyerek környezet függvénye meg is tudja változtatni a szülő környezet változóját, ha a set‑variable  cmdlet ugyanilyen –scope paraméterét megadjuk:

[17] PS I:\>function fv3{$a="másvalami";$a; (get-variable a -scope 1).value; set-variable a -scope 1 -value "változás"}

[18] PS I:\>fv3

másvalami

valami

[19] PS I:\>$a

változás

Itt a fv3 függvényben vége felé megváltoztatom a szülő $a változóját „változás”-ra.

A 0 és a legfelső környezetre némiképp egyszerűbb szintaxissal is hivatkozhatunk:

[25] PS I:\>$c=1

[26] PS I:\>function kie{$c=2; "Én c-m:$local:c";"Te c-d:$global:c"}

[27] PS I:\>kie

Én c-m:2

Te c-d:1

[28] PS I:\>function ront{$c=2; $local:c=3;$global:c=4;"Én c-m:$local:c";"Te c-d:$global:c"}

[29] PS I:\>ront

Én c-m:3

Te c-d:4

Egyébként vigyázni kell nagyon a függvényekkel! Az alábbi kis példában, ha a programozó abból a feltételezésből indul ki, hogy a $b az úgyis 0 kezdetben, így a $b=$b+5 értéke 5 lesz, akkor nagyot fog csalódni:

[21] PS I:\>$b=10

[22] PS I:\>function elront{$b=$b+5; $b}

[23] PS I:\>elront

15

[24] PS I:\>$b

10

Mi történt itt? A láthatóság miatt az elront függvényben az értékadás jobb oldalán szereplő $b az a szülő $b-je, a bal oldali $b már a függvény belső $b-je. Tehát – bár a nevük ugyanaz – tárhely szempontjából különbözőek.

Tipp

A függvények belső változóit mindig értékadás után kezdjük el használni, nehogy tévedésből a szülő környezet által definiált ugyanolyan nevű változó értékével kezdjünk el dolgozni.

Ha nem szeretnénk, hogy egy változónkhoz valamelyik gyerek környezet hozzáférhessen, akkor nyilvánítsuk privátnak ezt a változót:

[32] PS I:\>$private:priv=1

[33] PS I:\>function latom{"Privát: $priv"}

[34] PS I:\>latom

Privát:

[35] PS I:\>$priv

1

Ha egy függvénynek mégis ennek értékével kell dolgoznia, akkor természetesen paraméterátadással ez megtehető minden további nélkül, lényeg az, hogy a privát változókat a gyerek környezet nem fogja tudni a szülő tudta nélkül megváltoztatni.

Azonban azért így sem lehetünk teljes biztonságban, hiszen a get-variable és set-variable cmdletekkel még a privát változókat is elérhetjük:

[36] PS C:\> $private:priv=1

[37] PS C:\> function latom{"Privát: $((get-variable priv -scope 1).value)"}

[38] PS C:\> latom

Privát: 1

[39] PS C:\> function ront{set-variable priv -scope 1 -value 99}

[40] PS C:\> ront

[41] PS C:\> $priv

99

A fenti példában láthatjuk, hogy annak ellenére, hogy privátnak definiáltam a $priv változómat, ennek ellenére a latom függvényem is el tudta érni a get-variable segítségével, sőt, a ront függvényem még meg is tudta változtatni az értékét.

Nézzünk további lehetőségeket! Definiáltam egy scope nevű függvényt, amellyel az „aa” betűkkel kezdődő nevű, helyi változónak látszó változókat listázom ki:

[44] PS C:\> function scope {get-variable aa* -Scope local}

[45] PS C:\> scope

Ez alaphelyzetben nem ad találatot. Most definiálok egy $aa_felső változót, nézzük sajátjának tekinti-e a függvényem:

[47] PS C:\> $aa_felső = 1

[48] PS C:\> scope

Ez sem adott találatot. Most szintén a PowerShell legfelsőbb szintjén definiálok egy újabb változót, de egy speciális opció, az AllScope megadásával:

[50] PS C:\> New-Variable -Name aa_mindenütt -Value 2 -Option AllScope

[51] PS C:\> scope

 

Name                           Value

----                           -----

aa_mindenütt                   2

Ebből az látható, hogy a függvény is sajátjának érzi az $aa_mindenütt változót! Olyannyira, hogy meg is lehet változtatni az értékét függvényből is:

[53] PS C:\> function scope-allscope {$aa_mindenütt++}

[54] PS C:\> scope-allscope

[55] PS C:\> $aa_mindenütt

3

És természetesen ha egy függvény definiál egy ugyanilyen nevű változót, akkor az nem újként jön létre, hanem a korábban létrehozott kap új értéket:

[56] PS C:\> function scope-újmindenütt {$aa_mindenütt = 10}

[57] PS C:\> scope-újmindenütt

[58] PS C:\> $aa_mindenütt

10

Privát, privát, privát

Egy Private felhasználást láttunk már, de nézzük ezt egy picit részletesebben. Amit korábban mutattam, a $Private:változó formátumban azt a New-Variable cmdlettel is természetesen el lehet érni:

[26] PS C:\> New-Variable -name titkos -Value "titok" -Option private

[27] PS C:\> $titkos

titok

[28] PS C:\> function miez {$titkos}

[29] PS C:\> miez

A fenti példában a $titok változó alapban nem látható a gyerekkörnyezetként létrejövő függvényemben. Miután a TAB-kiegészítés is függvényként fut, ezért az ilyen változók neveit nem lehet kiegészíttetni sem. Viszont a Get-Variable látja a saját scope-jában:

[30] PS C:\> Get-Variable ti*

 

Name                           Value

----                           -----

titkos                         titok

Viszont van egy másik Private beállítás is, ez nem -option, hanem –visibility:

[31] PS C:\> New-Variable -name titkos2 -Value "titok2" -Visibility private

[32] PS C:\> function miez {$titkos2}

[33] PS C:\> miez

titok2

[34] PS C:\> Get-Variable ti*

 

Name                           Value

----                           -----

titkos                         titok

Látható, hogy az így felvett változó már láthatóság szempontjából elérhető egy al-scope-ból, de a Get‑Variable nem látja. És most jön a meglepetés:

[36] PS C:\> $titkos2

Cannot access the variable '$titkos2' because it is a private variable

At line:1 char:9

+ $titkos2 <<<<

    + CategoryInfo          : PermissionDenied: (titkos2:String) [], SessionS

   tateException

    + FullyQualifiedErrorId : VariableIsPrivate

A saját scope-ból nem szólítható meg. Ennek értelme nem a globális scope-ban van, hanem majd a következő fejezet végén nyer értelmet, és majd a modulok tárgyalásánál.



Word To HTML Converter