В языках программирования связывание имен — это ассоциация сущностей (данных и/или кода) с идентификаторами . [1] Говорят, что идентификатор, привязанный к объекту , ссылается на этот объект. В машинных языках нет встроенного понятия идентификаторов, но связывание имени с объектом как сервис и нотация для программиста реализуется языками программирования. Связывание тесно связано с областью действия , поскольку область действия определяет, какие имена привязаны к каким объектам — в каких местах в программном коде ( лексически ) и в каком из возможных путей выполнения ( временно ).
Использование идентификатора id в контексте, который устанавливает привязку для id, называется связывающим (или определяющим) вхождением. Во всех других вхождениях (например, в выражениях , назначениях и вызовах подпрограмм ) идентификатор обозначает то, к чему он привязан; такие вхождения называются применяемыми вхождениями.
Примером статической привязки является прямой вызов функции C : функция, на которую ссылается идентификатор, не может изменяться во время выполнения.
Примером динамического связывания является динамическая диспетчеризация , как в вызове виртуального метода C++ . Поскольку конкретный тип полиморфного объекта неизвестен до времени выполнения (в общем случае), выполняемая функция динамически связана. Возьмем, к примеру, следующий код Java :
public void foo ( java . util . List < String > list ) { list . add ( "bar" ); }
List
является интерфейсом , поэтому list
должен ссылаться на его подтипlist
. может ссылаться на LinkedList
, ArrayList
или на какой-либо другой подтип .List
Метод, на который ссылается add
, неизвестен до времени выполнения. В языке C, в котором нет динамического связывания, аналогичная цель может быть достигнута путем вызова функции, на которую указывает переменная или выражение типа указателя на функцию , значение которого неизвестно до тех пор, пока оно не будет вычислено во время выполнения.
Повторное связывание не следует путать с мутацией или присвоением.
Рассмотрим следующий код Java :
LinkedList < String > list ; list = new LinkedList < String > (); list . add ( "foo" ); list = null ; { LinkedList < Integer > list = new LinkedList < Integer > (); list . add ( Integer ( 2 )); }
Идентификатор list
привязан к переменной в первой строке; во второй переменной присваивается объект (связанный список строк). Связанный список, на который ссылается переменная, затем мутируется, добавляя строку в список. Затем переменной присваивается константа null
. В последней строке идентификатор повторно привязывается к области действия блока. Операции внутри блока обращаются к новой переменной, а не к переменной, ранее привязанной к list
.
Позднее статическое связывание — это вариант связывания где-то между статическим и динамическим связыванием. Рассмотрим следующий пример PHP :
класс A { public static $word = "hello" ; public static function hello () { print self :: $word ; } }класс B расширяет A { public static $word = "bye" ; }Б :: привет ();
В этом примере интерпретатор PHP связывает ключевое слово self
inside A::hello()
с class A
, и поэтому вызов to B::hello()
выдает строку "hello". Если бы семантика self::$word
была основана на позднем статическом связывании, то результатом было бы "bye".
Начиная с версии PHP 5.3 поддерживается позднее статическое связывание. [3] В частности, если бы self::$word
вышеприведенный код был изменен так, static::$word
как показано в следующем блоке, где ключевое слово static
будет привязано только во время выполнения, то результатом вызова B::hello()
будет «bye»:
класс A { public static $word = "hello" ; public static function hello () { print static :: $word ; } }класс B расширяет A { public static $word = "bye" ; }Б :: привет ();